├── public ├── favicon.ico ├── robots.txt ├── img │ ├── dashboard.png │ ├── login-office.jpeg │ ├── login-office-dark.jpeg │ ├── create-account-office.jpeg │ ├── forgot-password-office.jpeg │ ├── create-account-office-dark.jpeg │ ├── forgot-password-office-dark.jpeg │ ├── twitter.svg │ └── github.svg ├── mix-manifest.json ├── .htaccess ├── js │ ├── charts-bars.js │ ├── charts-pie.js │ ├── focus-trap.js │ ├── init-alpine.js │ └── charts-lines.js ├── web.config └── index.php ├── bootstrap ├── cache │ └── .gitignore └── app.php ├── storage ├── logs │ └── .gitignore ├── app │ ├── public │ │ └── .gitignore │ └── .gitignore └── framework │ ├── testing │ └── .gitignore │ ├── sessions │ └── .gitignore │ └── .gitignore ├── database ├── .gitignore ├── seeders │ └── DatabaseSeeder.php ├── migrations │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2020_05_21_100000_create_teams_table.php │ ├── 2020_05_21_200000_create_team_user_table.php │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ ├── 2020_09_19_062623_create_sessions_table.php │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_200000_add_two_factor_columns_to_users_table.php │ └── 2019_12_14_000001_create_personal_access_tokens_table.php └── factories │ └── UserFactory.php ├── resources ├── js │ ├── app.js │ └── bootstrap.js ├── css │ └── app.css ├── views │ ├── components │ │ ├── label.blade.php │ │ ├── input-error.blade.php │ │ ├── section-border.blade.php │ │ ├── dropdown-link.blade.php │ │ ├── action-section.blade.php │ │ ├── section-title.blade.php │ │ ├── input.blade.php │ │ ├── button.blade.php │ │ ├── authentication-card.blade.php │ │ ├── danger-button.blade.php │ │ ├── validation-errors.blade.php │ │ ├── secondary-button.blade.php │ │ ├── action-message.blade.php │ │ ├── application-mark.blade.php │ │ ├── dialog-modal.blade.php │ │ ├── authentication-card-logo.blade.php │ │ ├── nav-link.blade.php │ │ ├── responsive-nav-link.blade.php │ │ ├── form-section.blade.php │ │ ├── switchable-team.blade.php │ │ ├── confirmation-modal.blade.php │ │ ├── dropdown.blade.php │ │ ├── modal.blade.php │ │ ├── confirms-password.blade.php │ │ ├── application-logo.blade.php │ │ └── welcome.blade.php │ ├── layouts │ │ ├── menu.blade.php │ │ ├── mobile-menu.blade.php │ │ ├── guest.blade.php │ │ └── app.blade.php │ ├── api │ │ └── index.blade.php │ ├── teams │ │ ├── create.blade.php │ │ ├── show.blade.php │ │ ├── create-team-form.blade.php │ │ ├── delete-team-form.blade.php │ │ └── update-team-name-form.blade.php │ ├── auth │ │ ├── reset-password.blade.php │ │ ├── verify-email.blade.php │ │ ├── two-factor-challenge.blade.php │ │ ├── forgot-password.blade.php │ │ ├── login.blade.php │ │ └── register.blade.php │ ├── profile │ │ ├── update-password-form.blade.php │ │ ├── show.blade.php │ │ ├── delete-user-form.blade.php │ │ ├── update-profile-information-form.blade.php │ │ ├── two-factor-authentication-form.blade.php │ │ └── logout-other-browser-sessions-form.blade.php │ ├── charts.blade.php │ ├── pagination.blade.php │ └── modals.blade.php └── lang │ └── en │ ├── pagination.php │ ├── auth.php │ └── passwords.php ├── .gitattributes ├── tests ├── TestCase.php ├── Unit │ └── ExampleTest.php ├── Feature │ └── ExampleTest.php └── CreatesApplication.php ├── .gitignore ├── .styleci.yml ├── .editorconfig ├── app ├── Models │ ├── Membership.php │ ├── Team.php │ └── User.php ├── Http │ ├── Middleware │ │ ├── EncryptCookies.php │ │ ├── VerifyCsrfToken.php │ │ ├── TrimStrings.php │ │ ├── TrustHosts.php │ │ ├── PreventRequestsDuringMaintenance.php │ │ ├── Authenticate.php │ │ ├── TrustProxies.php │ │ └── RedirectIfAuthenticated.php │ ├── Controllers │ │ └── Controller.php │ └── Kernel.php ├── Actions │ ├── Jetstream │ │ ├── DeleteTeam.php │ │ ├── UpdateTeamName.php │ │ ├── CreateTeam.php │ │ ├── DeleteUser.php │ │ └── AddTeamMember.php │ └── Fortify │ │ ├── PasswordValidationRules.php │ │ ├── ResetUserPassword.php │ │ ├── UpdateUserProfileInformation.php │ │ ├── UpdateUserPassword.php │ │ └── CreateNewUser.php ├── Providers │ ├── BroadcastServiceProvider.php │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── EventServiceProvider.php │ ├── FortifyServiceProvider.php │ ├── RouteServiceProvider.php │ └── JetstreamServiceProvider.php ├── View │ └── Components │ │ ├── alert.php │ │ ├── AppLayout.php │ │ └── GuestLayout.php ├── Exceptions │ └── Handler.php ├── Console │ └── Kernel.php └── Policies │ └── TeamPolicy.php ├── routes ├── channels.php ├── api.php ├── console.php └── web.php ├── server.php ├── webpack.mix.js ├── .github └── FUNDING.yml ├── config ├── cors.php ├── services.php ├── view.php ├── jetstream.php ├── hashing.php ├── sanctum.php ├── broadcasting.php ├── filesystems.php ├── queue.php ├── logging.php ├── cache.php ├── mail.php ├── auth.php ├── fortify.php └── database.php ├── .env.example ├── LICENSE ├── README.md ├── phpunit.xml ├── package.json ├── artisan └── composer.json /public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | *.sqlite-journal 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | require('./bootstrap'); 2 | 3 | import 'alpinejs' 4 | -------------------------------------------------------------------------------- /public/img/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miten5/larawind/HEAD/public/img/dashboard.png -------------------------------------------------------------------------------- /public/img/login-office.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miten5/larawind/HEAD/public/img/login-office.jpeg -------------------------------------------------------------------------------- /public/mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/js/app.js": "/js/app.js", 3 | "/css/app.css": "/css/app.css" 4 | } 5 | -------------------------------------------------------------------------------- /public/img/login-office-dark.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miten5/larawind/HEAD/public/img/login-office-dark.jpeg -------------------------------------------------------------------------------- /public/img/create-account-office.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miten5/larawind/HEAD/public/img/create-account-office.jpeg -------------------------------------------------------------------------------- /public/img/forgot-password-office.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miten5/larawind/HEAD/public/img/forgot-password-office.jpeg -------------------------------------------------------------------------------- /resources/css/app.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss/base'; 2 | @import 'tailwindcss/components'; 3 | @import 'tailwindcss/utilities'; 4 | -------------------------------------------------------------------------------- /public/img/create-account-office-dark.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miten5/larawind/HEAD/public/img/create-account-office-dark.jpeg -------------------------------------------------------------------------------- /public/img/forgot-password-office-dark.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miten5/larawind/HEAD/public/img/forgot-password-office-dark.jpeg -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | *.js linguist-vendored 5 | CHANGELOG.md export-ignore 6 | -------------------------------------------------------------------------------- /resources/views/components/label.blade.php: -------------------------------------------------------------------------------- 1 | @props(['value']) 2 | 3 | -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | compiled.php 2 | config.php 3 | down 4 | events.scanned.php 5 | maintenance.php 6 | routes.php 7 | routes.scanned.php 8 | schedule-* 9 | services.json 10 | -------------------------------------------------------------------------------- /resources/views/components/input-error.blade.php: -------------------------------------------------------------------------------- 1 | @props(['for']) 2 | 3 | @error($for) 4 |

merge(['class' => 'text-sm text-red-600']) }}>{{ $message }}

5 | @enderror 6 | -------------------------------------------------------------------------------- /resources/views/components/section-border.blade.php: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /resources/views/layouts/menu.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | merge(['class' => 'block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out']) }}>{{ $slot }} 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /resources/views/components/action-section.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | {{ $content }} 6 |
7 |
8 |
-------------------------------------------------------------------------------- /resources/views/components/section-title.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ $title }}

4 | 5 |

6 | {{ $description }} 7 |

8 |
9 |
10 | -------------------------------------------------------------------------------- /app/Models/Membership.php: -------------------------------------------------------------------------------- 1 | false]) 2 | 3 | merge(['class' => 'block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input']) !!}> -------------------------------------------------------------------------------- /resources/views/components/button.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/Unit/ExampleTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /resources/views/components/authentication-card.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{ $logo }} 4 |
5 | 6 |
7 | {{ $slot }} 8 |
9 |
10 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | purge(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/views/components/danger-button.blade.php: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /resources/views/components/validation-errors.blade.php: -------------------------------------------------------------------------------- 1 | @if ($errors->any()) 2 |
3 |
Whoops! Something went wrong.
4 | 5 | 10 |
11 | @endif 12 | -------------------------------------------------------------------------------- /resources/views/api/index.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('API Tokens') }} 5 |

6 |
7 | 8 |
9 |
10 | @livewire('api.api-token-manager') 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /resources/views/teams/create.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Create Team') }} 5 |

6 |
7 | 8 |
9 |
10 | @livewire('teams.create-team-form') 11 |
12 |
13 |
-------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | merge(['type' => 'button', 'class' => 'inline-flex items-center px-4 py-2 bg-white border border-gray-300 rounded-md font-semibold text-xs text-gray-700 uppercase tracking-widest shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150']) }}> 2 | {{ $slot }} 3 | 4 | -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 18 | 19 | $response->assertStatus(200); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /resources/views/components/action-message.blade.php: -------------------------------------------------------------------------------- 1 | @props(['on']) 2 | 3 |
merge(['class' => 'text-sm text-gray-600']) }}> 8 | {{ $slot ?? 'Saved.' }} 9 |
10 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustHosts.php: -------------------------------------------------------------------------------- 1 | allSubdomainsOfApplicationUrl(), 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Middleware/PreventRequestsDuringMaintenance.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /resources/views/components/dialog-modal.blade.php: -------------------------------------------------------------------------------- 1 | @props(['id' => null, 'maxWidth' => null]) 2 | 3 | 4 |
5 |
6 | {{ $title }} 7 |
8 | 9 |
10 | {{ $content }} 11 |
12 |
13 | 14 |
15 | {{ $footer }} 16 |
17 |
18 | -------------------------------------------------------------------------------- /tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 18 | return route('login'); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/View/Components/alert.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 18 | }); 19 | -------------------------------------------------------------------------------- /app/View/Components/AppLayout.php: -------------------------------------------------------------------------------- 1 | title = $title; 19 | } 20 | 21 | /** 22 | * Get the view / contents that represents the component. 23 | * 24 | * @return \Illuminate\View\View 25 | */ 26 | public function render() 27 | { 28 | return view('layouts.app'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | get('/user', function (Request $request) { 18 | return $request->user(); 19 | }); 20 | -------------------------------------------------------------------------------- /server.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | $uri = urldecode( 11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 12 | ); 13 | 14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 15 | // built-in PHP web server. This provides a convenient way to test a Laravel 16 | // application without having installed a "real" web server software here. 17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /app/View/Components/GuestLayout.php: -------------------------------------------------------------------------------- 1 | title = $title; 19 | } 20 | 21 | /** 22 | * Get the view / contents that represents the component. 23 | * 24 | * @return \Illuminate\View\View 25 | */ 26 | public function render() 27 | { 28 | return view('layouts.guest'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /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').postCss('resources/css/app.css', 'public/css', [ 15 | require('postcss-import'), 16 | require('tailwindcss'), 17 | ]); 18 | -------------------------------------------------------------------------------- /resources/views/components/nav-link.blade.php: -------------------------------------------------------------------------------- 1 | @props(['active']) 2 | 3 | @php 4 | $classes = ($active ?? false) 5 | ? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out' 6 | : 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out'; 7 | @endphp 8 | 9 | merge(['class' => $classes]) }}> 10 | {{ $slot }} 11 | 12 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 19 | })->purpose('Display an inspiring quote'); 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [miten5] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | TeamPolicy::class, 18 | ]; 19 | 20 | /** 21 | * Register any authentication / authorization services. 22 | * 23 | * @return void 24 | */ 25 | public function boot() 26 | { 27 | // 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/img/twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/views/components/responsive-nav-link.blade.php: -------------------------------------------------------------------------------- 1 | @props(['active']) 2 | 3 | @php 4 | $classes = ($active ?? false) 5 | ? 'block pl-3 pr-4 py-2 border-l-4 border-indigo-400 text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out' 6 | : 'block pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out'; 7 | @endphp 8 | 9 | merge(['class' => $classes]) }}> 10 | {{ $slot }} 11 | 12 | -------------------------------------------------------------------------------- /public/img/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustProxies.php: -------------------------------------------------------------------------------- 1 | merge(['class' => 'mb-8 bg-white rounded-lg shadow-md dark:bg-gray-800']) }}> 4 |
5 |
6 |
7 |
8 |
9 | {{ $form }} 10 |
11 |
12 | 13 | @if (isset($actions)) 14 |
15 | {{ $actions }} 16 |
17 | @endif 18 |
19 |
20 |
21 | -------------------------------------------------------------------------------- /resources/views/teams/show.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Team Settings') }} 5 |

6 |
7 | 8 |
9 |
10 | @livewire('teams.update-team-name-form', ['team' => $team]) 11 | 12 | @livewire('teams.team-member-manager', ['team' => $team]) 13 | 14 | @if (Gate::check('delete', $team) && ! $team->personal_team) 15 | 16 | 17 |
18 | @livewire('teams.delete-team-form', ['team' => $team]) 19 |
20 | @endif 21 |
22 |
23 |
-------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | [ 19 | SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | * 26 | * @return void 27 | */ 28 | public function boot() 29 | { 30 | // 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Your password has been reset!', 17 | 'sent' => 'We have emailed your password reset link!', 18 | 'throttled' => 'Please wait before retrying.', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that email address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /app/Http/Middleware/RedirectIfAuthenticated.php: -------------------------------------------------------------------------------- 1 | check()) { 25 | return redirect(RouteServiceProvider::HOME); 26 | } 27 | } 28 | 29 | return $next($request); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/Actions/Fortify/ResetUserPassword.php: -------------------------------------------------------------------------------- 1 | $this->passwordRules(), 24 | ])->validateWithBag('updatePassword'); 25 | 26 | $user->forceFill([ 27 | 'password' => Hash::make($input['password']), 28 | ])->save(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token'); 19 | $table->timestamp('created_at')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('password_resets'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2020_05_21_100000_create_teams_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->foreignId('user_id')->index(); 19 | $table->string('name'); 20 | $table->boolean('personal_team'); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::drop('teams'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Actions/Jetstream/UpdateTeamName.php: -------------------------------------------------------------------------------- 1 | authorize('update', $team); 22 | 23 | Validator::make($input, [ 24 | 'name' => ['required', 'string', 'max:255'], 25 | ])->validateWithBag('updateTeamName'); 26 | 27 | $team->forceFill([ 28 | 'name' => $input['name'], 29 | ])->save(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /resources/views/components/switchable-team.blade.php: -------------------------------------------------------------------------------- 1 | @props(['team', 'component' => 'dropdown-link']) 2 | 3 |
4 | @method('PUT') 5 | @csrf 6 | 7 | 8 | 9 | 10 | 11 |
12 | @if (Auth::user()->isCurrentTeam($team)) 13 | 14 | @endif 15 | 16 |
{{ $team->name }}
17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | $this->faker->name, 27 | 'email' => $this->faker->unique()->safeEmail, 28 | 'email_verified_at' => now(), 29 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 30 | 'remember_token' => Str::random(10), 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /public/js/charts-bars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * For usage, visit Chart.js docs https://www.chartjs.org/docs/latest/ 3 | */ 4 | const barConfig = { 5 | type: 'bar', 6 | data: { 7 | labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], 8 | datasets: [ 9 | { 10 | label: 'Shoes', 11 | backgroundColor: '#0694a2', 12 | // borderColor: window.chartColors.red, 13 | borderWidth: 1, 14 | data: [-3, 14, 52, 74, 33, 90, 70], 15 | }, 16 | { 17 | label: 'Bags', 18 | backgroundColor: '#7e3af2', 19 | // borderColor: window.chartColors.blue, 20 | borderWidth: 1, 21 | data: [66, 33, 43, 12, 54, 62, 84], 22 | }, 23 | ], 24 | }, 25 | options: { 26 | responsive: true, 27 | legend: { 28 | display: false, 29 | }, 30 | }, 31 | } 32 | 33 | const barsCtx = document.getElementById('bars') 34 | window.myBar = new Chart(barsCtx, barConfig) 35 | -------------------------------------------------------------------------------- /app/Actions/Jetstream/CreateTeam.php: -------------------------------------------------------------------------------- 1 | authorize('create', Jetstream::newTeamModel()); 22 | 23 | Validator::make($input, [ 24 | 'name' => ['required', 'string', 'max:255'], 25 | ])->validateWithBag('createTeam'); 26 | 27 | return $user->ownedTeams()->create([ 28 | 'name' => $input['name'], 29 | 'personal_team' => false, 30 | ]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2020_05_21_200000_create_team_user_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->foreignId('team_id'); 19 | $table->foreignId('user_id'); 20 | $table->string('role')->nullable(); 21 | $table->timestamps(); 22 | 23 | $table->unique(['team_id', 'user_id']); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::drop('team_user'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /config/cors.php: -------------------------------------------------------------------------------- 1 | ['api/*'], 19 | 20 | 'allowed_methods' => ['*'], 21 | 22 | 'allowed_origins' => ['*'], 23 | 24 | 'allowed_origins_patterns' => [], 25 | 26 | 'allowed_headers' => ['*'], 27 | 28 | 'exposed_headers' => [], 29 | 30 | 'max_age' => 0, 31 | 32 | 'supports_credentials' => false, 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Larawind 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=http://larawind.test 6 | 7 | LOG_CHANNEL=stack 8 | 9 | DB_CONNECTION=mysql 10 | DB_HOST=127.0.0.1 11 | DB_PORT=3306 12 | DB_DATABASE=larawind 13 | DB_USERNAME=root 14 | DB_PASSWORD= 15 | 16 | BROADCAST_DRIVER=log 17 | CACHE_DRIVER=file 18 | QUEUE_CONNECTION=sync 19 | SESSION_DRIVER=database 20 | SESSION_LIFETIME=120 21 | 22 | REDIS_HOST=127.0.0.1 23 | REDIS_PASSWORD=null 24 | REDIS_PORT=6379 25 | 26 | MAIL_MAILER=smtp 27 | MAIL_HOST=smtp.mailtrap.io 28 | MAIL_PORT=2525 29 | MAIL_USERNAME=null 30 | MAIL_PASSWORD=null 31 | MAIL_ENCRYPTION=null 32 | MAIL_FROM_ADDRESS=null 33 | MAIL_FROM_NAME="${APP_NAME}" 34 | 35 | AWS_ACCESS_KEY_ID= 36 | AWS_SECRET_ACCESS_KEY= 37 | AWS_DEFAULT_REGION=us-east-1 38 | AWS_BUCKET= 39 | 40 | PUSHER_APP_ID= 41 | PUSHER_APP_KEY= 42 | PUSHER_APP_SECRET= 43 | PUSHER_APP_CLUSTER=mt1 44 | 45 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 46 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 47 | -------------------------------------------------------------------------------- /resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | window._ = require('lodash'); 2 | 3 | /** 4 | * We'll load the axios HTTP library which allows us to easily issue requests 5 | * to our Laravel back-end. This library automatically handles sending the 6 | * CSRF token as a header based on the value of the "XSRF" token cookie. 7 | */ 8 | 9 | window.axios = require('axios'); 10 | 11 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 12 | 13 | /** 14 | * Echo exposes an expressive API for subscribing to channels and listening 15 | * for events that are broadcast by Laravel. Echo and event broadcasting 16 | * allows your team to easily build robust real-time web applications. 17 | */ 18 | 19 | // import Echo from 'laravel-echo'; 20 | 21 | // window.Pusher = require('pusher-js'); 22 | 23 | // window.Echo = new Echo({ 24 | // broadcaster: 'pusher', 25 | // key: process.env.MIX_PUSHER_APP_KEY, 26 | // cluster: process.env.MIX_PUSHER_APP_CLUSTER, 27 | // forceTLS: true 28 | // }); 29 | -------------------------------------------------------------------------------- /app/Models/Team.php: -------------------------------------------------------------------------------- 1 | 'boolean', 19 | ]; 20 | 21 | /** 22 | * The attributes that are mass assignable. 23 | * 24 | * @var array 25 | */ 26 | protected $fillable = [ 27 | 'name', 28 | 'personal_team', 29 | ]; 30 | 31 | /** 32 | * The event map for the model. 33 | * 34 | * @var array 35 | */ 36 | protected $dispatchesEvents = [ 37 | 'created' => TeamCreated::class, 38 | 'updated' => TeamUpdated::class, 39 | 'deleted' => TeamDeleted::class, 40 | ]; 41 | } 42 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire')->hourly(); 28 | } 29 | 30 | /** 31 | * Register the commands for the application. 32 | * 33 | * @return void 34 | */ 35 | protected function commands() 36 | { 37 | $this->load(__DIR__.'/Commands'); 38 | 39 | require base_path('routes/console.php'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /database/migrations/2019_08_19_000000_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('uuid')->unique(); 19 | $table->text('connection'); 20 | $table->text('queue'); 21 | $table->longText('payload'); 22 | $table->longText('exception'); 23 | $table->timestamp('failed_at')->useCurrent(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('failed_jobs'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /resources/views/layouts/mobile-menu.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 8 | -------------------------------------------------------------------------------- /database/migrations/2020_09_19_062623_create_sessions_table.php: -------------------------------------------------------------------------------- 1 | string('id')->primary(); 18 | $table->foreignId('user_id')->nullable()->index(); 19 | $table->string('ip_address', 45)->nullable(); 20 | $table->text('user_agent')->nullable(); 21 | $table->text('payload'); 22 | $table->integer('last_activity')->index(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('sessions'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /resources/views/layouts/guest.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ config('app.name', 'Laravel') }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | {{ $slot }} 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /public/js/charts-pie.js: -------------------------------------------------------------------------------- 1 | /** 2 | * For usage, visit Chart.js docs https://www.chartjs.org/docs/latest/ 3 | */ 4 | const pieConfig = { 5 | type: 'doughnut', 6 | data: { 7 | datasets: [ 8 | { 9 | data: [33, 33, 33], 10 | /** 11 | * These colors come from Tailwind CSS palette 12 | * https://tailwindcss.com/docs/customizing-colors/#default-color-palette 13 | */ 14 | backgroundColor: ['#0694a2', '#1c64f2', '#7e3af2'], 15 | label: 'Dataset 1', 16 | }, 17 | ], 18 | labels: ['Shoes', 'Shirts', 'Bags'], 19 | }, 20 | options: { 21 | responsive: true, 22 | cutoutPercentage: 80, 23 | /** 24 | * Default legends are ugly and impossible to style. 25 | * See examples in charts.html to add your own legends 26 | * */ 27 | legend: { 28 | display: false, 29 | }, 30 | }, 31 | } 32 | 33 | // change this to the id of your chart element in HMTL 34 | const pieCtx = document.getElementById('pie') 35 | window.myPie = new Chart(pieCtx, pieConfig) 36 | -------------------------------------------------------------------------------- /app/Providers/FortifyServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | ], 22 | 23 | 'postmark' => [ 24 | 'token' => env('POSTMARK_TOKEN'), 25 | ], 26 | 27 | 'ses' => [ 28 | 'key' => env('AWS_ACCESS_KEY_ID'), 29 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 30 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 31 | ], 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->timestamp('email_verified_at')->nullable(); 21 | $table->string('password'); 22 | $table->rememberToken(); 23 | $table->string('current_team_id')->nullable(); 24 | $table->text('profile_photo_path')->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('users'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Miten Patel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_200000_add_two_factor_columns_to_users_table.php: -------------------------------------------------------------------------------- 1 | text('two_factor_secret') 18 | ->after('password') 19 | ->nullable(); 20 | 21 | $table->text('two_factor_recovery_codes') 22 | ->after('two_factor_secret') 23 | ->nullable(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::table('users', function (Blueprint $table) { 35 | $table->dropColumn('two_factor_secret'); 36 | $table->dropColumn('two_factor_recovery_codes'); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->morphs('tokenable'); 19 | $table->string('name'); 20 | $table->string('token', 64)->unique(); 21 | $table->text('abilities')->nullable(); 22 | $table->timestamp('last_used_at')->nullable(); 23 | $table->timestamp('expires_at')->nullable()->after('last_used_at'); 24 | $table->timestamps(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::dropIfExists('personal_access_tokens'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/Actions/Fortify/UpdateUserProfileInformation.php: -------------------------------------------------------------------------------- 1 | ['required', 'string', 'max:255'], 22 | 'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)], 23 | 'photo' => ['nullable', 'image', 'max:1024'], 24 | ])->validateWithBag('updateProfileInformation'); 25 | 26 | if (isset($input['photo'])) { 27 | $user->updateProfilePhoto($input['photo']); 28 | } 29 | 30 | $user->forceFill([ 31 | 'name' => $input['name'], 32 | 'email' => $input['email'], 33 | ])->save(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /config/jetstream.php: -------------------------------------------------------------------------------- 1 | 'livewire', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Features 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Some of Jetstream's features are optional. You may disable the features 26 | | by removing them from this array. You're free to only remove some of 27 | | these features or you can even remove all of these if you need to. 28 | | 29 | */ 30 | 31 | 'features' => [ 32 | Features::profilePhotos(), 33 | Features::api(), 34 | Features::teams(), 35 | ], 36 | 37 | ]; 38 | -------------------------------------------------------------------------------- /app/Actions/Fortify/UpdateUserPassword.php: -------------------------------------------------------------------------------- 1 | ['required', 'string'], 24 | 'password' => $this->passwordRules(), 25 | ])->after(function ($validator) use ($user, $input) { 26 | if (! Hash::check($input['current_password'], $user->password)) { 27 | $validator->errors()->add('current_password', __('The provided password does not match your current password.')); 28 | } 29 | })->validateWithBag('updatePassword'); 30 | 31 | $user->forceFill([ 32 | 'password' => Hash::make($input['password']), 33 | ])->save(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /resources/views/components/confirmation-modal.blade.php: -------------------------------------------------------------------------------- 1 | @props(['id' => null, 'maxWidth' => null]) 2 | 3 | 4 |
5 |
6 |
7 | 8 | 9 | 10 |
11 | 12 |
13 |

14 | {{ $title }} 15 |

16 | 17 |
18 | {{ $content }} 19 |
20 |
21 |
22 |
23 | 24 |
25 | {{ $footer }} 26 |
27 |
28 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | get('/dashboard', function () { 21 | // return view('dashboard'); 22 | // })->name('dashboard'); 23 | 24 | 25 | Route::group(['middleware' => ['auth:sanctum', 'verified']], function () { 26 | Route::view('dashboard', 'dashboard')->name('dashboard'); 27 | Route::view('forms', 'forms')->name('forms'); 28 | Route::view('cards', 'cards')->name('cards'); 29 | Route::view('charts', 'charts')->name('charts'); 30 | Route::view('buttons', 'buttons')->name('buttons'); 31 | Route::view('modals', 'modals')->name('modals'); 32 | Route::view('tables', 'tables')->name('tables'); 33 | Route::view('calendar', 'calendar')->name('calendar'); 34 | }); 35 | -------------------------------------------------------------------------------- /public/web.config: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Larawind - Laravel 10.0+ Jetstream and Tailwind CSS Admin Theme 2 | 3 | This project is created with [Laravel Jetstream](https://jetstream.laravel.com/1.x/introduction.html) Framework and [Tailwind CSS](https://tailwindcss.com), the admin environment is desing by [Windmill Dashboard](https://windmill-dashboard.vercel.app/). 4 | 5 | ## Requirements 6 | 7 | - Laravel installer 8 | - Composer 9 | - Npm installer 10 | 11 | ## Installation 12 | 13 | ``` 14 | # Clone the repository from GitHub and open the directory: 15 | git clone https://github.com/miten5/larawind.git 16 | 17 | # cd into your project directory 18 | cd larawind 19 | 20 | #install composer and npm packages 21 | composer install 22 | npm install && npm run dev 23 | 24 | # Start prepare the environment: 25 | cp .env.example .env // setup database credentials 26 | php artisan key:generate 27 | php artisan migrate 28 | php artisan storage:link 29 | 30 | # Run your server 31 | php artisan serve 32 | 33 | ``` 34 | 35 | If you like my work [Buy me a coffee](https://www.buymeacoffee.com/miten5) 36 | 37 | ### Project made possible thanks to: 38 | 39 | - [Laravel Jetstream](https://jetstream.laravel.com/1.x/introduction.html) 40 | - [Tailwind CSS](https://tailwindcss.com/) 41 | - [Windmill Dashboard](https://windmill-dashboard.vercel.app/) 42 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 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 | 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "npm run development -- --watch", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --disable-host-check --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "@tailwindcss/ui": "^0.5.0", 14 | "axios": "^0.19", 15 | "cross-env": "^7.0", 16 | "laravel-mix": "^5.0.1", 17 | "lodash": "^4.17.19", 18 | "postcss-import": "^12.0.1", 19 | "resolve-url-loader": "^3.1.0", 20 | "tailwindcss": "^1.3.0", 21 | "tailwindcss-multi-theme": "1.0.3", 22 | "vue-template-compiler": "^2.6.12" 23 | }, 24 | "dependencies": { 25 | "alpinejs": "^2.8.1", 26 | "turbolinks": "^5.2.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /resources/views/teams/create-team-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ __('Team Details') }} 4 | 5 | 6 | 7 | {{ __('Create a new team to collaborate with others on projects.') }} 8 | 9 | 10 | 11 |
12 | 13 | 14 |
15 | {{ $this->user->name }} 16 | 17 |
18 |
{{ $this->user->name }}
19 |
{{ $this->user->email }}
20 |
21 |
22 |
23 | 24 |
25 | 26 | 27 | 28 |
29 |
30 | 31 | 32 | 33 | {{ __('Create') }} 34 | 35 | 36 |
37 | -------------------------------------------------------------------------------- /resources/views/auth/reset-password.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | @csrf 11 | 12 | 13 | 14 |
15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 |
23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 | {{ __('Reset Password') }} 32 | 33 |
34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /app/Actions/Jetstream/DeleteUser.php: -------------------------------------------------------------------------------- 1 | deletesTeams = $deletesTeams; 27 | } 28 | 29 | /** 30 | * Delete the given user. 31 | * 32 | * @param mixed $user 33 | * @return void 34 | */ 35 | public function delete($user) 36 | { 37 | DB::transaction(function () use ($user) { 38 | $this->deleteTeams($user); 39 | 40 | $user->delete(); 41 | }); 42 | } 43 | 44 | /** 45 | * Delete the teams and team associations attached to the user. 46 | * 47 | * @param mixed $user 48 | * @return void 49 | */ 50 | protected function deleteTeams($user) 51 | { 52 | $user->teams()->detach(); 53 | 54 | $user->ownedTeams->each(function ($team) { 55 | $this->deletesTeams->delete($team); 56 | }); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/Models/User.php: -------------------------------------------------------------------------------- 1 | 'datetime', 50 | ]; 51 | 52 | /** 53 | * The accessors to append to the model's array form. 54 | * 55 | * @var array 56 | */ 57 | protected $appends = [ 58 | 'profile_photo_url', 59 | ]; 60 | } 61 | -------------------------------------------------------------------------------- /resources/views/profile/update-password-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 | 9 |
10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | {{ __('Saved.') }} 25 | 26 | 27 | 28 | {{ __('Save') }} 29 | 30 | 31 |
-------------------------------------------------------------------------------- /resources/views/components/dropdown.blade.php: -------------------------------------------------------------------------------- 1 | @props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white']) 2 | 3 | @php 4 | switch ($align) { 5 | case 'left': 6 | $alignmentClasses = 'origin-top-left left-0'; 7 | break; 8 | case 'top': 9 | $alignmentClasses = 'origin-top'; 10 | break; 11 | case 'right': 12 | default: 13 | $alignmentClasses = 'origin-top-right right-0'; 14 | break; 15 | } 16 | 17 | switch ($width) { 18 | case '48': 19 | $width = 'w-48'; 20 | break; 21 | } 22 | @endphp 23 | 24 |
25 |
26 | {{ $trigger }} 27 |
28 | 29 | 43 |
44 | -------------------------------------------------------------------------------- /resources/views/auth/verify-email.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | {{ __('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.') }} 9 |
10 | 11 | @if (session('status') == 'verification-link-sent') 12 |
13 | {{ __('A new verification link has been sent to the email address you provided during registration.') }} 14 |
15 | @endif 16 | 17 |
18 |
19 | @csrf 20 | 21 |
22 | 23 | {{ __('Resend Verification Email') }} 24 | 25 |
26 |
27 | 28 |
29 | @csrf 30 | 31 | 34 |
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /public/js/focus-trap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Limit focus to focusable elements inside `element` 3 | * @param {HTMLElement} element - DOM element to focus trap inside 4 | * @return {Function} cleanup function 5 | */ 6 | function focusTrap(element) { 7 | const focusableElements = getFocusableElements(element) 8 | const firstFocusableEl = focusableElements[0] 9 | const lastFocusableEl = focusableElements[focusableElements.length - 1] 10 | 11 | // Wait for the case the element was not yet rendered 12 | setTimeout(() => firstFocusableEl.focus(), 50) 13 | 14 | /** 15 | * Get all focusable elements inside `element` 16 | * @param {HTMLElement} element - DOM element to focus trap inside 17 | * @return {HTMLElement[]} List of focusable elements 18 | */ 19 | function getFocusableElements(element = document) { 20 | return [ 21 | ...element.querySelectorAll( 22 | 'a, button, details, input, select, textarea, [tabindex]:not([tabindex="-1"])' 23 | ), 24 | ].filter((e) => !e.hasAttribute('disabled')) 25 | } 26 | 27 | function handleKeyDown(e) { 28 | const TAB = 9 29 | const isTab = e.key.toLowerCase() === 'tab' || e.keyCode === TAB 30 | 31 | if (!isTab) return 32 | 33 | if (e.shiftKey) { 34 | if (document.activeElement === firstFocusableEl) { 35 | lastFocusableEl.focus() 36 | e.preventDefault() 37 | } 38 | } else { 39 | if (document.activeElement === lastFocusableEl) { 40 | firstFocusableEl.focus() 41 | e.preventDefault() 42 | } 43 | } 44 | } 45 | 46 | element.addEventListener('keydown', handleKeyDown) 47 | 48 | return function cleanup() { 49 | element.removeEventListener('keydown', handleKeyDown) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /resources/views/components/modal.blade.php: -------------------------------------------------------------------------------- 1 | @props(['id', 'maxWidth']) 2 | 3 | @php 4 | $id = $id ?? md5($attributes->wire('model')); 5 | 6 | switch ($maxWidth ?? '2xl') { 7 | case 'sm': 8 | $maxWidth = 'sm:max-w-sm'; 9 | break; 10 | case 'md': 11 | $maxWidth = 'sm:max-w-md'; 12 | break; 13 | case 'lg': 14 | $maxWidth = 'sm:max-w-lg'; 15 | break; 16 | case 'xl': 17 | $maxWidth = 'sm:max-w-xl'; 18 | break; 19 | case '2xl': 20 | default: 21 | $maxWidth = 'sm:max-w-2xl'; 22 | break; 23 | } 24 | @endphp 25 | 26 | -------------------------------------------------------------------------------- /app/Actions/Fortify/CreateNewUser.php: -------------------------------------------------------------------------------- 1 | ['required', 'string', 'max:255'], 26 | 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 27 | 'password' => $this->passwordRules(), 28 | ])->validate(); 29 | 30 | return DB::transaction(function () use ($input) { 31 | return tap(User::create([ 32 | 'name' => $input['name'], 33 | 'email' => $input['email'], 34 | 'password' => Hash::make($input['password']), 35 | ]), function (User $user) { 36 | $this->createTeam($user); 37 | }); 38 | }); 39 | } 40 | 41 | /** 42 | * Create a personal team for the user. 43 | * 44 | * @param \App\Models\User $user 45 | * @return void 46 | */ 47 | protected function createTeam(User $user) 48 | { 49 | $user->ownedTeams()->save(Team::forceCreate([ 50 | 'user_id' => $user->id, 51 | 'name' => explode(' ', $user->name, 2)[0]."'s Team", 52 | 'personal_team' => true, 53 | ])); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 1024, 48 | 'threads' => 2, 49 | 'time' => 2, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | configureRateLimiting(); 39 | 40 | $this->routes(function () { 41 | Route::middleware('web') 42 | ->group(base_path('routes/web.php')); 43 | 44 | Route::prefix('api') 45 | ->middleware('api') 46 | ->group(base_path('routes/api.php')); 47 | }); 48 | } 49 | 50 | /** 51 | * Configure the rate limiters for the application. 52 | * 53 | * @return void 54 | */ 55 | protected function configureRateLimiting() 56 | { 57 | RateLimiter::for('api', function (Request $request) { 58 | return Limit::perMinute(60); 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /resources/views/components/confirms-password.blade.php: -------------------------------------------------------------------------------- 1 | @props(['title' => __('Confirm Password'), 'content' => __('For your security, please confirm your password to continue.'), 'button' => __('Confirm')]) 2 | 3 | @php 4 | $confirmableId = md5($attributes->wire('then')); 5 | @endphp 6 | 7 | wire('then') }} 9 | x-data 10 | x-ref="span" 11 | x-on:click="$wire.startConfirmingPassword('{{ $confirmableId }}')" 12 | x-on:password-confirmed.window="setTimeout(() => $event.detail.id === '{{ $confirmableId }}' && $refs.span.dispatchEvent(new CustomEvent('then', { bubbles: false })), 250);" 13 | > 14 | {{ $slot }} 15 | 16 | 17 | @once 18 | 19 | 20 | {{ $title }} 21 | 22 | 23 | 24 | {{ $content }} 25 | 26 |
27 | 31 | 32 | 33 |
34 |
35 | 36 | 37 | 38 | Nevermind 39 | 40 | 41 | 42 | {{ $button }} 43 | 44 | 45 |
46 | @endonce 47 | -------------------------------------------------------------------------------- /config/sanctum.php: -------------------------------------------------------------------------------- 1 | explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1,127.0.0.1:8000,::1')), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Expiration Minutes 21 | |-------------------------------------------------------------------------- 22 | | 23 | | This value controls the number of minutes until an issued token will be 24 | | considered expired. If this value is null, personal access tokens do 25 | | not expire. This won't tweak the lifetime of first-party sessions. 26 | | 27 | */ 28 | 29 | 'expiration' => null, 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Sanctum Middleware 34 | |-------------------------------------------------------------------------- 35 | | 36 | | When authenticating your first-party SPA with Sanctum you may need to 37 | | customize some of the middleware Sanctum uses while processing the 38 | | request. You may change the middleware listed below as required. 39 | | 40 | */ 41 | 42 | 'middleware' => [ 43 | 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, 44 | 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, 45 | ], 46 | 47 | ]; 48 | -------------------------------------------------------------------------------- /resources/views/teams/delete-team-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ __('Delete Team') }} 4 | 5 | 6 | 7 | {{ __('Permanently delete this team.') }} 8 | 9 | 10 | 11 |
12 | {{ __('Once a team is deleted, all of its resources and data will be permanently deleted. Before deleting this team, please download any data or information regarding this team that you wish to retain.') }} 13 |
14 | 15 |
16 | 17 | {{ __('Delete Team') }} 18 | 19 |
20 | 21 | 22 | 23 | 24 | {{ __('Delete Team') }} 25 | 26 | 27 | 28 | {{ __('Are you sure you want to delete this team? Once a team is deleted, all of its resources and data will be permanently deleted.') }} 29 | 30 | 31 | 32 | 33 | {{ __('Nevermind') }} 34 | 35 | 36 | 37 | {{ __('Delete Team') }} 38 | 39 | 40 | 41 |
42 |
43 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Http\Kernel::class, 31 | App\Http\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Console\Kernel::class, 36 | App\Console\Kernel::class 37 | ); 38 | 39 | $app->singleton( 40 | Illuminate\Contracts\Debug\ExceptionHandler::class, 41 | App\Exceptions\Handler::class 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /public/js/init-alpine.js: -------------------------------------------------------------------------------- 1 | function data() { 2 | function getThemeFromLocalStorage() { 3 | // if user already changed the theme, use it 4 | if (window.localStorage.getItem('dark')) { 5 | return JSON.parse(window.localStorage.getItem('dark')) 6 | } 7 | 8 | // else return their preferences 9 | return ( 10 | !!window.matchMedia && 11 | window.matchMedia('(prefers-color-scheme: dark)').matches 12 | ) 13 | } 14 | 15 | function setThemeToLocalStorage(value) { 16 | window.localStorage.setItem('dark', value) 17 | } 18 | 19 | return { 20 | dark: getThemeFromLocalStorage(), 21 | toggleTheme() { 22 | this.dark = !this.dark 23 | setThemeToLocalStorage(this.dark) 24 | }, 25 | isSideMenuOpen: false, 26 | toggleSideMenu() { 27 | this.isSideMenuOpen = !this.isSideMenuOpen 28 | }, 29 | closeSideMenu() { 30 | this.isSideMenuOpen = false 31 | }, 32 | isNotificationsMenuOpen: false, 33 | toggleNotificationsMenu() { 34 | this.isNotificationsMenuOpen = !this.isNotificationsMenuOpen 35 | }, 36 | closeNotificationsMenu() { 37 | this.isNotificationsMenuOpen = false 38 | }, 39 | isProfileMenuOpen: false, 40 | toggleProfileMenu() { 41 | this.isProfileMenuOpen = !this.isProfileMenuOpen 42 | }, 43 | closeProfileMenu() { 44 | this.isProfileMenuOpen = false 45 | }, 46 | isPagesMenuOpen: false, 47 | togglePagesMenu() { 48 | this.isPagesMenuOpen = !this.isPagesMenuOpen 49 | }, 50 | // Modal 51 | isModalOpen: false, 52 | trapCleanup: null, 53 | openModal() { 54 | this.isModalOpen = true 55 | this.trapCleanup = focusTrap(document.querySelector('#modal')) 56 | }, 57 | closeModal() { 58 | this.isModalOpen = false 59 | this.trapCleanup() 60 | }, 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /config/broadcasting.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'null'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Broadcast Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the broadcast connections that will be used 26 | | to broadcast events to other systems or over websockets. Samples of 27 | | each available type of connection are provided inside this array. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'pusher' => [ 34 | 'driver' => 'pusher', 35 | 'key' => env('PUSHER_APP_KEY'), 36 | 'secret' => env('PUSHER_APP_SECRET'), 37 | 'app_id' => env('PUSHER_APP_ID'), 38 | 'options' => [ 39 | 'cluster' => env('PUSHER_APP_CLUSTER'), 40 | 'useTLS' => true, 41 | ], 42 | ], 43 | 44 | 'redis' => [ 45 | 'driver' => 'redis', 46 | 'connection' => 'default', 47 | ], 48 | 49 | 'log' => [ 50 | 'driver' => 'log', 51 | ], 52 | 53 | 'null' => [ 54 | 'driver' => 'null', 55 | ], 56 | 57 | ], 58 | 59 | ]; 60 | -------------------------------------------------------------------------------- /resources/views/teams/update-team-name-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ __('Team Name') }} 4 | 5 | 6 | 7 | {{ __('The team\'s name and owner information.') }} 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 |
16 | {{ $team->owner->name }} 17 | 18 |
19 |
{{ $team->owner->name }}
20 |
{{ $team->owner->email }}
21 |
22 |
23 |
24 | 25 | 26 |
27 | 28 | 29 | 34 | 35 | 36 |
37 |
38 | 39 | @if (Gate::check('update', $team)) 40 | 41 | 42 | {{ __('Saved.') }} 43 | 44 | 45 | 46 | {{ __('Save') }} 47 | 48 | 49 | @endif 50 |
51 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel/laravel", 3 | "type": "project", 4 | "description": "The Laravel Framework.", 5 | "keywords": [ 6 | "framework", 7 | "laravel" 8 | ], 9 | "license": "MIT", 10 | "require": { 11 | "php": "^8.1", 12 | "guzzlehttp/guzzle": "^7.0.1", 13 | "laravel/framework": "^10.0", 14 | "laravel/jetstream": "^3.0", 15 | "laravel/sanctum": "^3.2", 16 | "laravel/tinker": "^2.0", 17 | "livewire/livewire": "^2.0" 18 | }, 19 | "require-dev": { 20 | "spatie/laravel-ignition": "^2.0", 21 | "fakerphp/faker": "^1.15", 22 | "mockery/mockery": "^1.3.1", 23 | "nunomaduro/collision": "^7.0", 24 | "phpunit/phpunit": "^10.0" 25 | }, 26 | "config": { 27 | "optimize-autoloader": true, 28 | "preferred-install": "dist", 29 | "sort-packages": true 30 | }, 31 | "extra": { 32 | "laravel": { 33 | "dont-discover": [] 34 | } 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "App\\": "app/", 39 | "Database\\Factories\\": "database/factories/", 40 | "Database\\Seeders\\": "database/seeders/" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "Tests\\": "tests/" 46 | } 47 | }, 48 | "minimum-stability": "stable", 49 | "prefer-stable": true, 50 | "scripts": { 51 | "post-autoload-dump": [ 52 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", 53 | "@php artisan package:discover --ansi" 54 | ], 55 | "post-root-package-install": [ 56 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 57 | ], 58 | "post-create-project-cmd": [ 59 | "@php artisan key:generate --ansi" 60 | ] 61 | } 62 | } -------------------------------------------------------------------------------- /app/Providers/JetstreamServiceProvider.php: -------------------------------------------------------------------------------- 1 | configurePermissions(); 33 | 34 | Jetstream::createTeamsUsing(CreateTeam::class); 35 | Jetstream::updateTeamNamesUsing(UpdateTeamName::class); 36 | Jetstream::addTeamMembersUsing(AddTeamMember::class); 37 | Jetstream::deleteTeamsUsing(DeleteTeam::class); 38 | Jetstream::deleteUsersUsing(DeleteUser::class); 39 | } 40 | 41 | /** 42 | * Configure the roles and permissions that are available within the application. 43 | * 44 | * @return void 45 | */ 46 | protected function configurePermissions() 47 | { 48 | Jetstream::defaultApiTokenPermissions(['read']); 49 | 50 | Jetstream::role('admin', 'Administrator', [ 51 | 'create', 52 | 'read', 53 | 'update', 54 | 'delete', 55 | ])->description('Administrator users can perform any action.'); 56 | 57 | Jetstream::role('editor', 'Editor', [ 58 | 'read', 59 | 'create', 60 | 'update', 61 | ])->description('Editor users have the ability to read, create, and update.'); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /resources/views/profile/show.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | Profile 5 |

6 | 7 |

8 | {{ __('Profile Information') }} 9 |

10 | 11 | @livewire('profile.update-profile-information-form') 12 | 13 | 14 | 15 |
16 |

17 | {{ __('Update Password') }} 18 |

19 | 20 | @livewire('profile.update-password-form') 21 |
22 | 23 | @if (Laravel\Fortify\Features::canManageTwoFactorAuthentication()) 24 | 25 | 26 |
27 |

28 | {{ __('Two Factor Authentication') }} 29 |

30 | 31 | @livewire('profile.two-factor-authentication-form') 32 |
33 | @endif 34 | 35 | 36 | 37 |
38 |

39 | {{ __('Browser Sessions') }} 40 |

41 | 42 | @livewire('profile.logout-other-browser-sessions-form') 43 |
44 | 45 | 46 | 47 |
48 |

49 | {{ __('Delete Account') }} 50 |

51 | 52 | @livewire('profile.delete-user-form') 53 |
54 | 55 |
56 |
-------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class); 50 | 51 | $response = tap($kernel->handle( 52 | $request = Request::capture() 53 | ))->send(); 54 | 55 | $kernel->terminate($request, $response); 56 | -------------------------------------------------------------------------------- /public/js/charts-lines.js: -------------------------------------------------------------------------------- 1 | /** 2 | * For usage, visit Chart.js docs https://www.chartjs.org/docs/latest/ 3 | */ 4 | const lineConfig = { 5 | type: 'line', 6 | data: { 7 | labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], 8 | datasets: [ 9 | { 10 | label: 'Organic', 11 | /** 12 | * These colors come from Tailwind CSS palette 13 | * https://tailwindcss.com/docs/customizing-colors/#default-color-palette 14 | */ 15 | backgroundColor: '#0694a2', 16 | borderColor: '#0694a2', 17 | data: [43, 48, 40, 54, 67, 73, 70], 18 | fill: false, 19 | }, 20 | { 21 | label: 'Paid', 22 | fill: false, 23 | /** 24 | * These colors come from Tailwind CSS palette 25 | * https://tailwindcss.com/docs/customizing-colors/#default-color-palette 26 | */ 27 | backgroundColor: '#7e3af2', 28 | borderColor: '#7e3af2', 29 | data: [24, 50, 64, 74, 52, 51, 65], 30 | }, 31 | ], 32 | }, 33 | options: { 34 | responsive: true, 35 | /** 36 | * Default legends are ugly and impossible to style. 37 | * See examples in charts.html to add your own legends 38 | * */ 39 | legend: { 40 | display: false, 41 | }, 42 | tooltips: { 43 | mode: 'index', 44 | intersect: false, 45 | }, 46 | hover: { 47 | mode: 'nearest', 48 | intersect: true, 49 | }, 50 | scales: { 51 | x: { 52 | display: true, 53 | scaleLabel: { 54 | display: true, 55 | labelString: 'Month', 56 | }, 57 | }, 58 | y: { 59 | display: true, 60 | scaleLabel: { 61 | display: true, 62 | labelString: 'Value', 63 | }, 64 | }, 65 | }, 66 | }, 67 | } 68 | 69 | // change this to the id of your chart element in HMTL 70 | const lineCtx = document.getElementById('line') 71 | window.myLine = new Chart(lineCtx, lineConfig) 72 | -------------------------------------------------------------------------------- /resources/views/profile/delete-user-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | {{ __('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.') }} 5 |
6 | 7 |
8 | 9 | {{ __('Delete Account') }} 10 | 11 |
12 | 13 | 14 | 15 | 16 | {{ __('Delete Account') }} 17 | 18 | 19 | 20 | {{ __('Are you sure you want to delete your account? 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.') }} 21 | 22 |
23 | 24 | 25 | 26 |
27 |
28 | 29 | 30 | 31 | {{ __('Nevermind') }} 32 | 33 | 34 | 35 | {{ __('Delete Account') }} 36 | 37 | 38 |
39 |
40 |
-------------------------------------------------------------------------------- /resources/views/layouts/app.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{ $title }} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | @livewireStyles 28 | 32 | 33 | 34 | {{-- --}} 35 | 36 | 37 | 38 |
39 | @include('layouts.menu') 40 | @include('layouts.mobile-menu') 41 | 42 |
43 | @include('layouts.navigation-dropdown') 44 |
45 | {{ $slot }} 46 |
47 |
48 | 49 | 50 | @stack('modals') 51 | 52 | @livewireScripts 53 |
54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/Http/Kernel.php: -------------------------------------------------------------------------------- 1 | [ 33 | \App\Http\Middleware\EncryptCookies::class, 34 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 35 | \Illuminate\Session\Middleware\StartSession::class, 36 | \Laravel\Jetstream\Http\Middleware\AuthenticateSession::class, 37 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 38 | \App\Http\Middleware\VerifyCsrfToken::class, 39 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 40 | ], 41 | 42 | 'api' => [ 43 | 'throttle:api', 44 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 45 | ], 46 | ]; 47 | 48 | /** 49 | * The application's route middleware. 50 | * 51 | * These middleware may be assigned to groups or used individually. 52 | * 53 | * @var array 54 | */ 55 | protected $routeMiddleware = [ 56 | 'auth' => \App\Http\Middleware\Authenticate::class, 57 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 58 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 59 | 'can' => \Illuminate\Auth\Middleware\Authorize::class, 60 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 61 | 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 62 | 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 63 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 64 | 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 65 | ]; 66 | } 67 | -------------------------------------------------------------------------------- /resources/views/auth/two-factor-challenge.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 | {{ __('Please confirm access to your account by entering the authentication code provided by your authenticator application.') }} 10 |
11 | 12 |
13 | {{ __('Please confirm access to your account by entering one of your emergency recovery codes.') }} 14 |
15 | 16 | 17 | 18 |
19 | @csrf 20 | 21 |
22 | 23 | 24 |
25 | 26 |
27 | 28 | 29 |
30 | 31 |
32 | 40 | 41 | 49 | 50 | 51 | {{ __('Login') }} 52 | 53 |
54 |
55 |
56 |
57 |
58 | -------------------------------------------------------------------------------- /app/Actions/Jetstream/AddTeamMember.php: -------------------------------------------------------------------------------- 1 | authorize('addTeamMember', $team); 26 | 27 | $this->validate($team, $email, $role); 28 | 29 | $team->users()->attach( 30 | $newTeamMember = Jetstream::findUserByEmailOrFail($email), 31 | ['role' => $role] 32 | ); 33 | 34 | TeamMemberAdded::dispatch($team, $newTeamMember); 35 | } 36 | 37 | /** 38 | * Validate the add member operation. 39 | * 40 | * @param mixed $team 41 | * @param string $email 42 | * @param string|null $role 43 | * @return void 44 | */ 45 | protected function validate($team, string $email, ?string $role) 46 | { 47 | Validator::make([ 48 | 'email' => $email, 49 | 'role' => $role, 50 | ], $this->rules(), [ 51 | 'email.exists' => __('We were unable to find a registered user with this email address.'), 52 | ])->after( 53 | $this->ensureUserIsNotAlreadyOnTeam($team, $email) 54 | )->validateWithBag('addTeamMember'); 55 | } 56 | 57 | /** 58 | * Get the validation rules for adding a team member. 59 | * 60 | * @return array 61 | */ 62 | protected function rules() 63 | { 64 | return array_filter([ 65 | 'email' => ['required', 'email', 'exists:users'], 66 | 'role' => Jetstream::hasRoles() 67 | ? ['required', 'string', new Role] 68 | : null, 69 | ]); 70 | } 71 | 72 | /** 73 | * Ensure that the user is not already on the team. 74 | * 75 | * @param mixed $team 76 | * @param string $email 77 | * @return \Closure 78 | */ 79 | protected function ensureUserIsNotAlreadyOnTeam($team, string $email) 80 | { 81 | return function ($validator) use ($team, $email) { 82 | $validator->errors()->addIf( 83 | $team->hasUserWithEmail($email), 84 | 'email', 85 | __('This user already belongs to the team.') 86 | ); 87 | }; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/Policies/TeamPolicy.php: -------------------------------------------------------------------------------- 1 | belongsToTeam($team); 34 | } 35 | 36 | /** 37 | * Determine whether the user can create models. 38 | * 39 | * @param \App\Models\User $user 40 | * @return mixed 41 | */ 42 | public function create(User $user) 43 | { 44 | return true; 45 | } 46 | 47 | /** 48 | * Determine whether the user can update the model. 49 | * 50 | * @param \App\Models\User $user 51 | * @param \App\Models\Team $team 52 | * @return mixed 53 | */ 54 | public function update(User $user, Team $team) 55 | { 56 | return $user->ownsTeam($team); 57 | } 58 | 59 | /** 60 | * Determine whether the user can add team members. 61 | * 62 | * @param \App\Models\User $user 63 | * @param \App\Models\Team $team 64 | * @return mixed 65 | */ 66 | public function addTeamMember(User $user, Team $team) 67 | { 68 | return $user->ownsTeam($team); 69 | } 70 | 71 | /** 72 | * Determine whether the user can update team member permissions. 73 | * 74 | * @param \App\Models\User $user 75 | * @param \App\Models\Team $team 76 | * @return mixed 77 | */ 78 | public function updateTeamMember(User $user, Team $team) 79 | { 80 | return $user->ownsTeam($team); 81 | } 82 | 83 | /** 84 | * Determine whether the user can remove team members. 85 | * 86 | * @param \App\Models\User $user 87 | * @param \App\Models\Team $team 88 | * @return mixed 89 | */ 90 | public function removeTeamMember(User $user, Team $team) 91 | { 92 | return $user->ownsTeam($team); 93 | } 94 | 95 | /** 96 | * Determine whether the user can delete the model. 97 | * 98 | * @param \App\Models\User $user 99 | * @param \App\Models\Team $team 100 | * @return mixed 101 | */ 102 | public function delete(User $user, Team $team) 103 | { 104 | return $user->ownsTeam($team); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /resources/views/profile/update-profile-information-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @if (Laravel\Jetstream\Jetstream::managesProfilePhotos()) 5 |
6 | 7 | 15 | 16 | 17 | 18 | 19 |
20 | {{ $this->user->name }} 21 |
22 | 23 | 24 |
25 | 26 | 27 |
28 | 29 | 30 | {{ __('Select A New Photo') }} 31 | 32 | 33 | 34 |
35 | @endif 36 | 37 | 38 |
39 | 40 | 41 | 42 |
43 | 44 | 45 |
46 | 47 | 48 | 49 |
50 |
51 | 52 | 53 | 54 | {{ __('Saved.') }} 55 | 56 | 57 | 58 | {{ __('Save') }} 59 | 60 | 61 |
-------------------------------------------------------------------------------- /resources/views/profile/two-factor-authentication-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | @if ($this->enabled) 5 | {{ __('You have enabled two factor authentication.') }} 6 | @else 7 | {{ __('You have not enabled two factor authentication.') }} 8 | @endif 9 |

10 | 11 |
12 |

13 | {{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }} 14 |

15 |
16 | 17 | @if ($this->enabled) 18 | @if ($showingQrCode) 19 |
20 |

21 | {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application.') }} 22 |

23 |
24 | 25 |
26 | {!! $this->user->twoFactorQrCodeSvg() !!} 27 |
28 | @endif 29 | 30 | @if ($showingRecoveryCodes) 31 |
32 |

33 | {{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }} 34 |

35 |
36 | 37 |
38 | @foreach (json_decode(decrypt($this->user->two_factor_recovery_codes), true) as $code) 39 |
{{ $code }}
40 | @endforeach 41 |
42 | @endif 43 | @endif 44 | 45 |
46 | @if (! $this->enabled) 47 | 48 | {{ __('Enable') }} 49 | 50 | @else 51 | @if ($showingRecoveryCodes) 52 | 53 | {{ __('Regenerate Recovery Codes') }} 54 | 55 | @else 56 | 57 | {{ __('Show Recovery Codes') }} 58 | 59 | @endif 60 | 61 | 62 | {{ __('Disable') }} 63 | 64 | @endif 65 |
66 |
67 |
-------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DRIVER', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Default Cloud Filesystem Disk 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Many applications store files both locally and in the cloud. For this 24 | | reason, you may specify a default "cloud" driver here. This driver 25 | | will be bound as the Cloud disk implementation in the container. 26 | | 27 | */ 28 | 29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Filesystem Disks 34 | |-------------------------------------------------------------------------- 35 | | 36 | | Here you may configure as many filesystem "disks" as you wish, and you 37 | | may even configure multiple disks of the same driver. Defaults have 38 | | been setup for each driver as an example of the required options. 39 | | 40 | | Supported Drivers: "local", "ftp", "sftp", "s3" 41 | | 42 | */ 43 | 44 | 'disks' => [ 45 | 46 | 'local' => [ 47 | 'driver' => 'local', 48 | 'root' => storage_path('app'), 49 | ], 50 | 51 | 'public' => [ 52 | 'driver' => 'local', 53 | 'root' => storage_path('app/public'), 54 | 'url' => env('APP_URL').'/storage', 55 | 'visibility' => 'public', 56 | ], 57 | 58 | 's3' => [ 59 | 'driver' => 's3', 60 | 'key' => env('AWS_ACCESS_KEY_ID'), 61 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 62 | 'region' => env('AWS_DEFAULT_REGION'), 63 | 'bucket' => env('AWS_BUCKET'), 64 | 'url' => env('AWS_URL'), 65 | 'endpoint' => env('AWS_ENDPOINT'), 66 | ], 67 | 68 | ], 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Symbolic Links 73 | |-------------------------------------------------------------------------- 74 | | 75 | | Here you may configure the symbolic links that will be created when the 76 | | `storage:link` Artisan command is executed. The array keys should be 77 | | the locations of the links and the values should be their targets. 78 | | 79 | */ 80 | 81 | 'links' => [ 82 | public_path('storage') => storage_path('app/public'), 83 | ], 84 | 85 | ]; 86 | -------------------------------------------------------------------------------- /config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_CONNECTION', 'sync'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Queue Connections 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure the connection information for each server that 24 | | is used by your application. A default configuration has been added 25 | | for each back-end shipped with Laravel. You are free to add more. 26 | | 27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'table' => 'jobs', 40 | 'queue' => 'default', 41 | 'retry_after' => 90, 42 | ], 43 | 44 | 'beanstalkd' => [ 45 | 'driver' => 'beanstalkd', 46 | 'host' => 'localhost', 47 | 'queue' => 'default', 48 | 'retry_after' => 90, 49 | 'block_for' => 0, 50 | ], 51 | 52 | 'sqs' => [ 53 | 'driver' => 'sqs', 54 | 'key' => env('AWS_ACCESS_KEY_ID'), 55 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 56 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 57 | 'queue' => env('SQS_QUEUE', 'your-queue-name'), 58 | 'suffix' => env('SQS_SUFFIX'), 59 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 60 | ], 61 | 62 | 'redis' => [ 63 | 'driver' => 'redis', 64 | 'connection' => 'default', 65 | 'queue' => env('REDIS_QUEUE', 'default'), 66 | 'retry_after' => 90, 67 | 'block_for' => null, 68 | ], 69 | 70 | ], 71 | 72 | /* 73 | |-------------------------------------------------------------------------- 74 | | Failed Queue Jobs 75 | |-------------------------------------------------------------------------- 76 | | 77 | | These options configure the behavior of failed queue job logging so you 78 | | can control which database and table are used to store the jobs that 79 | | have failed. You may change them to any database / table you wish. 80 | | 81 | */ 82 | 83 | 'failed' => [ 84 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), 85 | 'database' => env('DB_CONNECTION', 'mysql'), 86 | 'table' => 'failed_jobs', 87 | ], 88 | 89 | ]; 90 | -------------------------------------------------------------------------------- /resources/views/components/application-logo.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/views/auth/forgot-password.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
6 | 8 | 10 |
11 |
12 |
13 |

Forgot password

14 | @if ($errors->any()) 15 |
16 |
Whoops! Something went wrong.
17 | 18 |
    19 | @foreach ($errors->all() as $error) 20 |
  • {{ $error }}
  • 21 | @endforeach 22 |
23 |
24 | @endif 25 | 26 | @if (session('status')) 27 |
28 | {{ session('status') }} 29 |
30 | @endif 31 | 32 |
33 | @csrf 34 | 40 | 41 | 42 | 47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | -------------------------------------------------------------------------------- /config/logging.php: -------------------------------------------------------------------------------- 1 | env('LOG_CHANNEL', 'stack'), 21 | 22 | /* 23 | |-------------------------------------------------------------------------- 24 | | Log Channels 25 | |-------------------------------------------------------------------------- 26 | | 27 | | Here you may configure the log channels for your application. Out of 28 | | the box, Laravel uses the Monolog PHP logging library. This gives 29 | | you a variety of powerful log handlers / formatters to utilize. 30 | | 31 | | Available Drivers: "single", "daily", "slack", "syslog", 32 | | "errorlog", "monolog", 33 | | "custom", "stack" 34 | | 35 | */ 36 | 37 | 'channels' => [ 38 | 'stack' => [ 39 | 'driver' => 'stack', 40 | 'channels' => ['single'], 41 | 'ignore_exceptions' => false, 42 | ], 43 | 44 | 'single' => [ 45 | 'driver' => 'single', 46 | 'path' => storage_path('logs/laravel.log'), 47 | 'level' => 'debug', 48 | ], 49 | 50 | 'daily' => [ 51 | 'driver' => 'daily', 52 | 'path' => storage_path('logs/laravel.log'), 53 | 'level' => 'debug', 54 | 'days' => 14, 55 | ], 56 | 57 | 'slack' => [ 58 | 'driver' => 'slack', 59 | 'url' => env('LOG_SLACK_WEBHOOK_URL'), 60 | 'username' => 'Laravel Log', 61 | 'emoji' => ':boom:', 62 | 'level' => 'critical', 63 | ], 64 | 65 | 'papertrail' => [ 66 | 'driver' => 'monolog', 67 | 'level' => 'debug', 68 | 'handler' => SyslogUdpHandler::class, 69 | 'handler_with' => [ 70 | 'host' => env('PAPERTRAIL_URL'), 71 | 'port' => env('PAPERTRAIL_PORT'), 72 | ], 73 | ], 74 | 75 | 'stderr' => [ 76 | 'driver' => 'monolog', 77 | 'handler' => StreamHandler::class, 78 | 'formatter' => env('LOG_STDERR_FORMATTER'), 79 | 'with' => [ 80 | 'stream' => 'php://stderr', 81 | ], 82 | ], 83 | 84 | 'syslog' => [ 85 | 'driver' => 'syslog', 86 | 'level' => 'debug', 87 | ], 88 | 89 | 'errorlog' => [ 90 | 'driver' => 'errorlog', 91 | 'level' => 'debug', 92 | ], 93 | 94 | 'null' => [ 95 | 'driver' => 'monolog', 96 | 'handler' => NullHandler::class, 97 | ], 98 | 99 | 'emergency' => [ 100 | 'path' => storage_path('logs/laravel.log'), 101 | ], 102 | ], 103 | 104 | ]; 105 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_DRIVER', 'file'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Cache Stores 26 | |-------------------------------------------------------------------------- 27 | | 28 | | Here you may define all of the cache "stores" for your application as 29 | | well as their drivers. You may even define multiple stores for the 30 | | same cache driver to group types of items stored in your caches. 31 | | 32 | */ 33 | 34 | 'stores' => [ 35 | 36 | 'apc' => [ 37 | 'driver' => 'apc', 38 | ], 39 | 40 | 'array' => [ 41 | 'driver' => 'array', 42 | 'serialize' => false, 43 | ], 44 | 45 | 'database' => [ 46 | 'driver' => 'database', 47 | 'table' => 'cache', 48 | 'connection' => null, 49 | ], 50 | 51 | 'file' => [ 52 | 'driver' => 'file', 53 | 'path' => storage_path('framework/cache/data'), 54 | ], 55 | 56 | 'memcached' => [ 57 | 'driver' => 'memcached', 58 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), 59 | 'sasl' => [ 60 | env('MEMCACHED_USERNAME'), 61 | env('MEMCACHED_PASSWORD'), 62 | ], 63 | 'options' => [ 64 | // Memcached::OPT_CONNECT_TIMEOUT => 2000, 65 | ], 66 | 'servers' => [ 67 | [ 68 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 69 | 'port' => env('MEMCACHED_PORT', 11211), 70 | 'weight' => 100, 71 | ], 72 | ], 73 | ], 74 | 75 | 'redis' => [ 76 | 'driver' => 'redis', 77 | 'connection' => 'cache', 78 | ], 79 | 80 | 'dynamodb' => [ 81 | 'driver' => 'dynamodb', 82 | 'key' => env('AWS_ACCESS_KEY_ID'), 83 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 84 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 85 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), 86 | 'endpoint' => env('DYNAMODB_ENDPOINT'), 87 | ], 88 | 89 | ], 90 | 91 | /* 92 | |-------------------------------------------------------------------------- 93 | | Cache Key Prefix 94 | |-------------------------------------------------------------------------- 95 | | 96 | | When utilizing a RAM based store such as APC or Memcached, there might 97 | | be other applications utilizing the same cache. So, we'll specify a 98 | | value to get prefixed to all our keys so we can avoid collisions. 99 | | 100 | */ 101 | 102 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'), 103 | 104 | ]; 105 | -------------------------------------------------------------------------------- /config/mail.php: -------------------------------------------------------------------------------- 1 | env('MAIL_MAILER', 'smtp'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Mailer Configurations 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure all of the mailers used by your application plus 24 | | their respective settings. Several examples have been configured for 25 | | you and you are free to add your own as your application requires. 26 | | 27 | | Laravel supports a variety of mail "transport" drivers to be used while 28 | | sending an e-mail. You will specify which one you are using for your 29 | | mailers below. You are free to add additional mailers as required. 30 | | 31 | | Supported: "smtp", "sendmail", "mailgun", "ses", 32 | | "postmark", "log", "array" 33 | | 34 | */ 35 | 36 | 'mailers' => [ 37 | 'smtp' => [ 38 | 'transport' => 'smtp', 39 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), 40 | 'port' => env('MAIL_PORT', 587), 41 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'), 42 | 'username' => env('MAIL_USERNAME'), 43 | 'password' => env('MAIL_PASSWORD'), 44 | 'timeout' => null, 45 | 'auth_mode' => null, 46 | ], 47 | 48 | 'ses' => [ 49 | 'transport' => 'ses', 50 | ], 51 | 52 | 'mailgun' => [ 53 | 'transport' => 'mailgun', 54 | ], 55 | 56 | 'postmark' => [ 57 | 'transport' => 'postmark', 58 | ], 59 | 60 | 'sendmail' => [ 61 | 'transport' => 'sendmail', 62 | 'path' => '/usr/sbin/sendmail -bs', 63 | ], 64 | 65 | 'log' => [ 66 | 'transport' => 'log', 67 | 'channel' => env('MAIL_LOG_CHANNEL'), 68 | ], 69 | 70 | 'array' => [ 71 | 'transport' => 'array', 72 | ], 73 | ], 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Global "From" Address 78 | |-------------------------------------------------------------------------- 79 | | 80 | | You may wish for all e-mails sent by your application to be sent from 81 | | the same address. Here, you may specify a name and address that is 82 | | used globally for all e-mails that are sent by your application. 83 | | 84 | */ 85 | 86 | 'from' => [ 87 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), 88 | 'name' => env('MAIL_FROM_NAME', 'Example'), 89 | ], 90 | 91 | /* 92 | |-------------------------------------------------------------------------- 93 | | Markdown Mail Settings 94 | |-------------------------------------------------------------------------- 95 | | 96 | | If you are using Markdown based email rendering, you may configure your 97 | | theme and component paths here, allowing you to customize the design 98 | | of the emails. Or, you may simply stick with the Laravel defaults! 99 | | 100 | */ 101 | 102 | 'markdown' => [ 103 | 'theme' => 'default', 104 | 105 | 'paths' => [ 106 | resource_path('views/vendor/mail'), 107 | ], 108 | ], 109 | 110 | ]; 111 | -------------------------------------------------------------------------------- /resources/views/charts.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | Charts 5 |

6 | 7 |

8 | Charts are provided by 9 | 10 | Chart.js 11 | 12 | . Note that the default legends are disabled and you should 13 | provide a description for your charts in HTML. See source code for 14 | examples. 15 |

16 | 17 |
18 | 19 |
20 |

21 | Doughnut/Pie 22 |

23 | 24 |
25 | 26 |
27 | 28 | Shirts 29 |
30 |
31 | 32 | Shoes 33 |
34 |
35 | 36 | Bags 37 |
38 |
39 |
40 | 41 |
42 |

43 | Lines 44 |

45 | 46 |
47 | 48 |
49 | 50 | Organic 51 |
52 |
53 | 54 | Paid 55 |
56 |
57 |
58 | 59 |
60 |

61 | Bars 62 |

63 | 64 |
65 | 66 |
67 | 68 | Shoes 69 |
70 |
71 | 72 | Bags 73 |
74 |
75 |
76 |
77 |
78 |
-------------------------------------------------------------------------------- /resources/views/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 |
11 |

12 | Login 13 |

14 | @if ($errors->any()) 15 |
16 |
Whoops! Something went wrong.
17 | 18 |
    19 | @foreach ($errors->all() as $error) 20 |
  • {{ $error }}
  • 21 | @endforeach 22 |
23 |
24 | @endif 25 | 26 | @if (session('status')) 27 |
28 | {{ session('status') }} 29 |
30 | @endif 31 |
32 | @csrf 33 | 37 | 41 | 44 | 45 | 48 |
49 | 50 |

51 | 52 | {{ __('Forgot your password?') }} 53 | 54 |

55 |
56 |
57 |
58 |
59 |
60 |
-------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session", "token" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | 44 | 'api' => [ 45 | 'driver' => 'token', 46 | 'provider' => 'users', 47 | 'hash' => false, 48 | ], 49 | ], 50 | 51 | /* 52 | |-------------------------------------------------------------------------- 53 | | User Providers 54 | |-------------------------------------------------------------------------- 55 | | 56 | | All authentication drivers have a user provider. This defines how the 57 | | users are actually retrieved out of your database or other storage 58 | | mechanisms used by this application to persist your user's data. 59 | | 60 | | If you have multiple user tables or models you may configure multiple 61 | | sources which represent each model / table. These sources may then 62 | | be assigned to any extra authentication guards you have defined. 63 | | 64 | | Supported: "database", "eloquent" 65 | | 66 | */ 67 | 68 | 'providers' => [ 69 | 'users' => [ 70 | 'driver' => 'eloquent', 71 | 'model' => App\Models\User::class, 72 | ], 73 | 74 | // 'users' => [ 75 | // 'driver' => 'database', 76 | // 'table' => 'users', 77 | // ], 78 | ], 79 | 80 | /* 81 | |-------------------------------------------------------------------------- 82 | | Resetting Passwords 83 | |-------------------------------------------------------------------------- 84 | | 85 | | You may specify multiple password reset configurations if you have more 86 | | than one user table or model in the application and you want to have 87 | | separate password reset settings based on the specific user types. 88 | | 89 | | The expire time is the number of minutes that the reset token should be 90 | | considered valid. This security feature keeps tokens short-lived so 91 | | they have less time to be guessed. You may change this as needed. 92 | | 93 | */ 94 | 95 | 'passwords' => [ 96 | 'users' => [ 97 | 'provider' => 'users', 98 | 'table' => 'password_resets', 99 | 'expire' => 60, 100 | 'throttle' => 60, 101 | ], 102 | ], 103 | 104 | /* 105 | |-------------------------------------------------------------------------- 106 | | Password Confirmation Timeout 107 | |-------------------------------------------------------------------------- 108 | | 109 | | Here you may define the amount of seconds before a password confirmation 110 | | times out and the user is prompted to re-enter their password via the 111 | | confirmation screen. By default, the timeout lasts for three hours. 112 | | 113 | */ 114 | 115 | 'password_timeout' => 10800, 116 | 117 | ]; 118 | -------------------------------------------------------------------------------- /config/fortify.php: -------------------------------------------------------------------------------- 1 | 'web', 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Fortify Password Broker 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Here you may specify which password broker Fortify can use when a user 27 | | is resetting their password. This configured value should match one 28 | | of your password brokers setup in your "auth" configuration file. 29 | | 30 | */ 31 | 32 | 'passwords' => 'users', 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Username / Email 37 | |-------------------------------------------------------------------------- 38 | | 39 | | This value defines which model attribute should be considered as your 40 | | application's "username" field. Typically, this might be the email 41 | | address of the users but you are free to change this value here. 42 | | 43 | | Out of the box, Fortify expects forgot password and reset password 44 | | requests to have a field named 'email'. If the application uses 45 | | another name for the field you may define it below as needed. 46 | | 47 | */ 48 | 49 | 'username' => 'email', 50 | 51 | 'email' => 'email', 52 | 53 | /* 54 | |-------------------------------------------------------------------------- 55 | | Home Path 56 | |-------------------------------------------------------------------------- 57 | | 58 | | Here you may configure the path where users will get redirected during 59 | | authentication or password reset when the operations are successful 60 | | and the user is authenticated. You are free to change this value. 61 | | 62 | */ 63 | 64 | 'home' => RouteServiceProvider::HOME, 65 | 66 | /* 67 | |-------------------------------------------------------------------------- 68 | | Fortify Routes Middleware 69 | |-------------------------------------------------------------------------- 70 | | 71 | | Here you may specify which middleware Fortify will assign to the routes 72 | | that it registers with the application. If necessary, you may change 73 | | these middleware but typically this provided default is preferred. 74 | | 75 | */ 76 | 77 | 'middleware' => ['web'], 78 | 79 | /* 80 | |-------------------------------------------------------------------------- 81 | | Rate Limiting 82 | |-------------------------------------------------------------------------- 83 | | 84 | | By default, Fortify will throttle logins to five requests per minute for 85 | | every email and IP address combination. However, if you would like to 86 | | specify a custom rate limiter to call then you may specify it here. 87 | | 88 | */ 89 | 90 | 'limiters' => [ 91 | 'login' => null, 92 | ], 93 | 94 | /* 95 | |-------------------------------------------------------------------------- 96 | | Features 97 | |-------------------------------------------------------------------------- 98 | | 99 | | Some of the Fortify features are optional. You may disable the features 100 | | by removing them from this array. You're free to only remove some of 101 | | these features or you can even remove all of these if you need to. 102 | | 103 | */ 104 | 105 | 'features' => [ 106 | Features::registration(), 107 | Features::resetPasswords(), 108 | // Features::emailVerification(), 109 | Features::updateProfileInformation(), 110 | Features::updatePasswords(), 111 | Features::twoFactorAuthentication(), 112 | ], 113 | 114 | ]; 115 | -------------------------------------------------------------------------------- /resources/views/profile/logout-other-browser-sessions-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | {{ __('If necessary, you may logout of all of your other browser sessions across all of your devices. If you feel your account has been compromised, you should also update your password.') }} 5 |
6 | 7 | @if (count($this->sessions) > 0) 8 |
9 | 10 | @foreach ($this->sessions as $session) 11 |
12 |
13 | @if ($session->agent->isDesktop()) 14 | 15 | 16 | 17 | @else 18 | 19 | 20 | 21 | 22 | 23 | @endif 24 |
25 | 26 |
27 |
28 | {{ $session->agent->platform() }} - {{ $session->agent->browser() }} 29 |
30 | 31 |
32 |
33 | {{ $session->ip_address }}, 34 | 35 | @if ($session->is_current_device) 36 | {{ __('This device') }} 37 | @else 38 | {{ __('Last active') }} {{ $session->last_active }} 39 | @endif 40 |
41 |
42 |
43 |
44 | @endforeach 45 |
46 | @endif 47 | 48 |
49 | 50 | {{ __('Logout Other Browser Sessions') }} 51 | 52 | 53 | 54 | {{ __('Done.') }} 55 | 56 |
57 | 58 | 59 | 60 | 61 | {{ __('Logout Other Browser Sessions') }} 62 | 63 | 64 | 65 | {{ __('Please enter your password to confirm you would like to logout of your other browser sessions across all of your devices.') }} 66 | 67 |
68 | 69 | 70 | 71 |
72 |
73 | 74 | 75 | 76 | {{ __('Nevermind') }} 77 | 78 | 79 | 80 | {{ __('Logout Other Browser Sessions') }} 81 | 82 | 83 |
84 |
85 |
-------------------------------------------------------------------------------- /resources/views/pagination.blade.php: -------------------------------------------------------------------------------- 1 | @if ($paginator->hasPages()) 2 |
5 | 6 | {!! __('Showing') !!} 7 | {{ $paginator->firstItem() }}-{{ $paginator->lastItem() }} 8 | {!! __('of') !!} 9 | {{ $paginator->total() }} 10 | 11 | 12 | 13 | 14 | 15 | 91 | 92 |
93 | @endif 94 | -------------------------------------------------------------------------------- /resources/views/modals.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | Modals 5 |

6 | 7 |
8 |

9 | This is possibly 10 | the most accessible a modal can get 11 | , using JavaScript. When opened, it uses 12 | assets/js/focus-trap.js 13 | to create a 14 | focus trap 15 | , which means that if you use your keyboard to navigate around, 16 | focus won't leak to the elements behind, staying inside the 17 | modal in a loop, until you take any action. 18 |

19 | 20 |

21 | Also, on small screens it is placed at the bottom of the screen, 22 | to account for larger devices and make it easier to click the 23 | larger buttons. 24 |

25 |
26 | 27 |
28 | 31 |
32 |
33 |
34 | 35 | 65 |
66 |
-------------------------------------------------------------------------------- /resources/views/auth/register.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 |
11 |

12 | Create account 13 |

14 | @if ($errors->any()) 15 |
16 |
Whoops! Something went wrong.
17 | 18 |
    19 | @foreach ($errors->all() as $error) 20 |
  • {{ $error }}
  • 21 | @endforeach 22 |
23 |
24 | @endif 25 | 26 | @if (session('status')) 27 |
28 | {{ session('status') }} 29 |
30 | @endif 31 | 32 |
33 | @csrf 34 | 38 | 42 | 46 | 52 | 53 | 54 | 57 |
58 | 59 |

60 | 61 | Already have an account? Login 62 | 63 |

64 |
65 |
66 |
67 |
68 |
69 |
-------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | env('DB_CONNECTION', 'mysql'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Database Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here are each of the database connections setup for your application. 26 | | Of course, examples of configuring each database platform that is 27 | | supported by Laravel is shown below to make development simple. 28 | | 29 | | 30 | | All database work in Laravel is done through the PHP PDO facilities 31 | | so make sure you have the driver for your particular database of 32 | | choice installed on your machine before you begin development. 33 | | 34 | */ 35 | 36 | 'connections' => [ 37 | 38 | 'sqlite' => [ 39 | 'driver' => 'sqlite', 40 | 'url' => env('DATABASE_URL'), 41 | 'database' => env('DB_DATABASE', database_path('database.sqlite')), 42 | 'prefix' => '', 43 | 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), 44 | ], 45 | 46 | 'mysql' => [ 47 | 'driver' => 'mysql', 48 | 'url' => env('DATABASE_URL'), 49 | 'host' => env('DB_HOST', '127.0.0.1'), 50 | 'port' => env('DB_PORT', '3306'), 51 | 'database' => env('DB_DATABASE', 'forge'), 52 | 'username' => env('DB_USERNAME', 'forge'), 53 | 'password' => env('DB_PASSWORD', ''), 54 | 'unix_socket' => env('DB_SOCKET', ''), 55 | 'charset' => 'utf8mb4', 56 | 'collation' => 'utf8mb4_unicode_ci', 57 | 'prefix' => '', 58 | 'prefix_indexes' => true, 59 | 'strict' => true, 60 | 'engine' => null, 61 | 'options' => extension_loaded('pdo_mysql') ? array_filter([ 62 | PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), 63 | ]) : [], 64 | ], 65 | 66 | 'pgsql' => [ 67 | 'driver' => 'pgsql', 68 | 'url' => env('DATABASE_URL'), 69 | 'host' => env('DB_HOST', '127.0.0.1'), 70 | 'port' => env('DB_PORT', '5432'), 71 | 'database' => env('DB_DATABASE', 'forge'), 72 | 'username' => env('DB_USERNAME', 'forge'), 73 | 'password' => env('DB_PASSWORD', ''), 74 | 'charset' => 'utf8', 75 | 'prefix' => '', 76 | 'prefix_indexes' => true, 77 | 'schema' => 'public', 78 | 'sslmode' => 'prefer', 79 | ], 80 | 81 | 'sqlsrv' => [ 82 | 'driver' => 'sqlsrv', 83 | 'url' => env('DATABASE_URL'), 84 | 'host' => env('DB_HOST', 'localhost'), 85 | 'port' => env('DB_PORT', '1433'), 86 | 'database' => env('DB_DATABASE', 'forge'), 87 | 'username' => env('DB_USERNAME', 'forge'), 88 | 'password' => env('DB_PASSWORD', ''), 89 | 'charset' => 'utf8', 90 | 'prefix' => '', 91 | 'prefix_indexes' => true, 92 | ], 93 | 94 | ], 95 | 96 | /* 97 | |-------------------------------------------------------------------------- 98 | | Migration Repository Table 99 | |-------------------------------------------------------------------------- 100 | | 101 | | This table keeps track of all the migrations that have already run for 102 | | your application. Using this information, we can determine which of 103 | | the migrations on disk haven't actually been run in the database. 104 | | 105 | */ 106 | 107 | 'migrations' => 'migrations', 108 | 109 | /* 110 | |-------------------------------------------------------------------------- 111 | | Redis Databases 112 | |-------------------------------------------------------------------------- 113 | | 114 | | Redis is an open source, fast, and advanced key-value store that also 115 | | provides a richer body of commands than a typical key-value system 116 | | such as APC or Memcached. Laravel makes it easy to dig right in. 117 | | 118 | */ 119 | 120 | 'redis' => [ 121 | 122 | 'client' => env('REDIS_CLIENT', 'phpredis'), 123 | 124 | 'options' => [ 125 | 'cluster' => env('REDIS_CLUSTER', 'redis'), 126 | 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), 127 | ], 128 | 129 | 'default' => [ 130 | 'url' => env('REDIS_URL'), 131 | 'host' => env('REDIS_HOST', '127.0.0.1'), 132 | 'password' => env('REDIS_PASSWORD', null), 133 | 'port' => env('REDIS_PORT', '6379'), 134 | 'database' => env('REDIS_DB', '0'), 135 | ], 136 | 137 | 'cache' => [ 138 | 'url' => env('REDIS_URL'), 139 | 'host' => env('REDIS_HOST', '127.0.0.1'), 140 | 'password' => env('REDIS_PASSWORD', null), 141 | 'port' => env('REDIS_PORT', '6379'), 142 | 'database' => env('REDIS_CACHE_DB', '1'), 143 | ], 144 | 145 | ], 146 | 147 | ]; 148 | -------------------------------------------------------------------------------- /resources/views/components/welcome.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 | Welcome to your Jetstream application! 8 |
9 | 10 |
11 | Laravel Jetstream provides a beautiful, robust starting point for your next Laravel application. Laravel is designed 12 | to help you build your application using a development environment that is simple, powerful, and enjoyable. We believe 13 | you should love expressing your creativity through programming, so we have spent time carefully crafting the Laravel 14 | ecosystem to be a breath of fresh air. We hope you love it. 15 |
16 |
17 | 18 |
19 |
20 |
21 | 22 | 23 |
24 | 25 |
26 |
27 | Laravel has wonderful documentation covering every aspect of the framework. Whether you're new to the framework or have previous experience, we recommend reading all of the documentation from beginning to end. 28 |
29 | 30 | 31 |
32 |
Explore the documentation
33 | 34 |
35 | 36 |
37 |
38 |
39 |
40 |
41 | 42 |
43 |
44 | 45 | 46 |
47 | 48 |
49 |
50 | Laracasts offers thousands of video tutorials on Laravel, PHP, and JavaScript development. Check them out, see for yourself, and massively level up your development skills in the process. 51 |
52 | 53 | 54 |
55 |
Start watching Laracasts
56 | 57 |
58 | 59 |
60 |
61 |
62 |
63 |
64 | 65 |
66 |
67 | 68 | 69 |
70 | 71 |
72 |
73 | Laravel Jetstream is built with Tailwind, an amazing utility first CSS framework that doesn't get in your way. You'll be amazed how easily you can build and maintain fresh, modern designs with this wonderful framework at your fingertips. 74 |
75 |
76 |
77 | 78 |
79 |
80 | 81 |
Authentication
82 |
83 | 84 |
85 |
86 | Authentication and registration views are included with Laravel Jetstream, as well as support for user email verification and resetting forgotten passwords. So, you're free to get started what matters most: building your application. 87 |
88 |
89 |
90 |
91 | --------------------------------------------------------------------------------