diff --git a/app/Http/Controllers/Settings/PasswordController.php b/app/Http/Controllers/Settings/PasswordController.php index cfa80337c..adcb1cd96 100644 --- a/app/Http/Controllers/Settings/PasswordController.php +++ b/app/Http/Controllers/Settings/PasswordController.php @@ -15,17 +15,12 @@ public function __construct() $this->middleware(Authenticate::class); } - public function edit() - { - return view('users.settings.password'); - } - public function update(UpdatePasswordRequest $request) { $this->dispatchNow(new UpdatePassword(Auth::user(), $request->newPassword())); $this->success('settings.password.updated'); - return redirect()->route('settings.password'); + return redirect()->route('settings.profile'); } } diff --git a/app/Http/Controllers/Settings/ProfileController.php b/app/Http/Controllers/Settings/ProfileController.php index 3dd16e7fe..db6ad1479 100644 --- a/app/Http/Controllers/Settings/ProfileController.php +++ b/app/Http/Controllers/Settings/ProfileController.php @@ -20,7 +20,7 @@ public function __construct() public function edit() { - return view('users.settings.profile'); + return view('users.settings.settings'); } public function update(UpdateProfileRequest $request) diff --git a/config/blade-ui-kit.php b/config/blade-ui-kit.php new file mode 100644 index 000000000..9f73fdbca --- /dev/null +++ b/config/blade-ui-kit.php @@ -0,0 +1,125 @@ + [ + // 'alert' => Components\Alerts\Alert::class, + 'avatar' => Components\Support\Avatar::class, + // 'carbon' => Components\DateTime\Carbon::class, + // 'checkbox' => Components\Forms\Inputs\Checkbox::class, + // 'color-picker' => Components\Forms\Inputs\ColorPicker::class, + // 'countdown' => Components\DateTime\Countdown::class, + // 'cron' => Components\Support\Cron::class, + // 'dropdown' => Components\Navigation\Dropdown::class, + // 'easy-mde' => Components\Editors\EasyMDE::class, + 'email' => Components\Forms\Inputs\Email::class, + // 'error' => Components\Forms\Error::class, + 'form' => Components\Forms\Form::class, + // 'form-button' => Components\Buttons\FormButton::class, + // 'html' => Components\Layouts\Html::class, + 'input' => Components\Forms\Inputs\Input::class, + 'label' => Components\Forms\Label::class, + // 'logout' => Components\Buttons\Logout::class, + // 'mapbox' => Components\Maps\Mapbox::class, + // 'markdown' => Components\Markdown\Markdown::class, + 'password' => Components\Forms\Inputs\Password::class, + // 'pikaday' => Components\Forms\Inputs\Pikaday::class, + // 'social-meta' => Components\Layouts\SocialMeta::class, + 'textarea' => Components\Forms\Inputs\Textarea::class, + // 'toc' => Components\Markdown\ToC::class, + // 'trix' => Components\Editors\Trix::class, + // 'unsplash' => Components\Support\Unsplash::class, + ], + + /* + |-------------------------------------------------------------------------- + | Livewire Components + |-------------------------------------------------------------------------- + | + | Below you reference all the Livewire components that should be loaded + | for your app. By default all components from Blade UI Kit are loaded in. + | + */ + + 'livewire' => [ + // + ], + + /* + |-------------------------------------------------------------------------- + | Components Prefix + |-------------------------------------------------------------------------- + | + | This value will set a prefix for all Blade UI Kit components. + | By default it's empty. This is useful if you want to avoid + | collision with components from other libraries. + | + | If set with "buk", for example, you can reference components like: + | + | + | + */ + + 'prefix' => '', + + /* + |-------------------------------------------------------------------------- + | Third Party Asset Libraries + |-------------------------------------------------------------------------- + | + | These settings hold reference to all third party libraries and their + | asset files served through a CDN. Individual components can require + | these asset files through their static `$assets` property. + | + */ + + 'assets' => [ + + 'alpine' => 'https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.3.5/dist/alpine.min.js', + + 'easy-mde' => [ + 'https://unpkg.com/easymde/dist/easymde.min.css', + 'https://unpkg.com/easymde/dist/easymde.min.js', + ], + + 'mapbox' => [ + 'https://api.mapbox.com/mapbox-gl-js/v1.8.1/mapbox-gl.css', + 'https://api.mapbox.com/mapbox-gl-js/v1.8.1/mapbox-gl.js', + ], + + 'moment' => [ + 'https://cdn.jsdelivr.net/npm/moment@2.26.0/moment.min.js', + 'https://cdn.jsdelivr.net/npm/moment-timezone@0.5.31/builds/moment-timezone-with-data.min.js', + ], + + 'pickr' => [ + 'https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/classic.min.css', + 'https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js', + ], + + 'pikaday' => [ + 'https://cdn.jsdelivr.net/npm/pikaday/css/pikaday.css', + 'https://cdn.jsdelivr.net/npm/pikaday/pikaday.js', + ], + + 'trix' => [ + 'https://unpkg.com/trix@1.2.3/dist/trix.css', + 'https://unpkg.com/trix@1.2.3/dist/trix.js', + ], + + ], + +]; diff --git a/resources/css/forms.css b/resources/css/forms.css index ddfb0d343..a0867846a 100644 --- a/resources/css/forms.css +++ b/resources/css/forms.css @@ -1,104 +1,104 @@ -.form-group { +.standard .form-group { @apply flex flex-col mb-4; } -label { +.standard label { @apply mb-1 text-gray-600 block uppercase text-sm; } -input[type='text'], -input[type='password'], -input[type='email'], -select { +.standard input[type='text'], +.standard input[type='password'], +.standard input[type='email'], +.standard select { @apply h-12; } -input[type='text'], -input[type='password'], -input[type='email'], -textarea, -select { +.standard input[type='text'], +.standard input[type='password'], +.standard input[type='email'], +.standard textarea, +.standard select { @apply rounded border-2 p-3 w-full; } -select { +.standard select { @apply appearance-none; } -input.nav-search { +.standard input.nav-search { @apply pl-10 pr-3 py-2; } -input[type='checkbox'] { +.standard input[type='checkbox'] { @apply mr-1; } -.help-block { +.standard .help-block { @apply text-red-500 text-sm; } /** Markdown editor **/ -.form-group .editor { +.standard .form-group .editor { @apply rounded-t-none; } -.form-group .editor-toolbar { +.standard .form-group .editor-toolbar { @apply border-2 border-b-0 rounded rounded-b-none border-gray-300; } -.form-group .CodeMirror { +.standard .form-group .CodeMirror { @apply border-2 rounded rounded-t-none border-gray-300; } /** Choices.js **/ -.choices__input.choices__input--cloned { +.standard .choices__input.choices__input--cloned { @apply hidden; } -.choices__inner { +.standard .choices__inner { @apply rounded border-2 border-gray-300 w-full bg-white h-12 p-2 flex items-center !important; } -.choices__list--dropdown { +.standard .choices__list--dropdown { @apply border-2 border-gray-300 !important; } -.choices__list--single { +.standard .choices__list--single { @apply p-0 !important; } -.choices__item { +.standard .choices__item { @apply text-sm bg-gray-200 text-gray-700 cursor-pointer rounded px-2 py-1 my-0 border-0 !important; } -.choices__item.choices__item--choice { +.standard .choices__item.choices__item--choice { @apply rounded-none py-2 !important; } -.choices__item.choices__item--choice.choices__item--selectable { +.standard .choices__item.choices__item--choice.choices__item--selectable { @apply bg-white rounded-none text-gray-700 p-2 !important; } -.choices__item.choices__item--choice.choices__item--selectable:hover { +.standard .choices__item.choices__item--choice.choices__item--selectable:hover { @apply bg-gray-200 !important; } -.choices__item.choices__item--selectable { +.standard .choices__item.choices__item--selectable { @apply bg-lio-500 border-lio-500 text-white !important; } -.choices__list--single > .choices__item.choices__item--selectable { +.standard .choices__list--single > .choices__item.choices__item--selectable { @apply bg-white text-gray-700 !important; } -.choices__item.is-highlighted { +.standard .choices__item.is-highlighted { @apply bg-lio-600 border-lio-600 text-white !important; } -.choices[data-type*='select-one']:after { +.standard .choices[data-type*='select-one']:after { border-color: theme('colors.gray.500') transparent transparent transparent !important; } -.choices[data-type*='select-one'] .choices__input { +.standard .choices[data-type*='select-one'] .choices__input { @apply rounded-none border-b-2 border-gray-300 !important; } diff --git a/resources/helpers.php b/resources/helpers.php index bd785d2b2..1601f7c17 100644 --- a/resources/helpers.php +++ b/resources/helpers.php @@ -10,6 +10,16 @@ function active($routes, bool $condition = true): string } } +if (! function_exists('is_active')) { + /** + * Determines if the given routes are active. + */ + function is_active($routes): string + { + return call_user_func_array([app('router'), 'is'], (array) $routes); + } +} + if (! function_exists('md_to_html')) { /** * Convert Markdown to HTML. diff --git a/resources/views/components/buttons/danger-button.blade.php b/resources/views/components/buttons/danger-button.blade.php new file mode 100644 index 000000000..ac3ece6fc --- /dev/null +++ b/resources/views/components/buttons/danger-button.blade.php @@ -0,0 +1,7 @@ +@props(['type' => 'button']) + + + + \ No newline at end of file diff --git a/resources/views/components/buttons/primary-button.blade.php b/resources/views/components/buttons/primary-button.blade.php new file mode 100644 index 000000000..f939eaa0c --- /dev/null +++ b/resources/views/components/buttons/primary-button.blade.php @@ -0,0 +1,7 @@ +@props(['type' => 'button']) + + + + \ No newline at end of file diff --git a/resources/views/layouts/base.blade.php b/resources/views/layouts/base.blade.php index 80ec4ddf2..5d7eaaa25 100644 --- a/resources/views/layouts/base.blade.php +++ b/resources/views/layouts/base.blade.php @@ -33,7 +33,7 @@ @livewireStyles - + @include('layouts._ads._banner') @include('layouts._nav') diff --git a/resources/views/layouts/settings.blade.php b/resources/views/layouts/settings.blade.php deleted file mode 100644 index 6d9060894..000000000 --- a/resources/views/layouts/settings.blade.php +++ /dev/null @@ -1,31 +0,0 @@ -@extends('layouts.base') - -@section('body') -
-
-
-

{{ $title }}

-
-
- - @include('layouts._alerts') - -
-
- @yield('content') -
- -
-

Settings

- -
-
-
-@endsection diff --git a/resources/views/users/settings/password.blade.php b/resources/views/users/settings/password.blade.php index 7c7c0d363..9c85b4377 100644 --- a/resources/views/users/settings/password.blade.php +++ b/resources/views/users/settings/password.blade.php @@ -1,35 +1,41 @@ @title('Password') -@extends('layouts.settings') +
+ +
+
+
+

Password Settings

+

Update the password used for logging into your account.

+
-@section('content') -
-
- @csrf - @method('PUT') +
- @if (Auth::user()->hasPassword()) - @formGroup('current_password') - - - @error('current_password') - @endFormGroup - @endif + @if (Auth::user()->hasPassword()) +
+ + +
+ @endif - @formGroup('password') - - - @error('password') - @endFormGroup +
+ New Password + +
- @formGroup('password_confirmation') - - - @endFormGroup +
+ Confirm New Password + +
-
- +
-
-
-@endsection + +
+ + Update Password + +
+
+ +
diff --git a/resources/views/users/settings/profile.blade.php b/resources/views/users/settings/profile.blade.php index bcb6c42d6..80726c18c 100644 --- a/resources/views/users/settings/profile.blade.php +++ b/resources/views/users/settings/profile.blade.php @@ -1,80 +1,80 @@ @title('Profile') -@extends('layouts.settings') +
+ +
+
-@section('content') -
-
- @csrf - @method('PUT') - -
- - Change your avatar on Gravatar. +

Profile

+

Update your profile information.

-
- - @formGroup('name') - - - @error('name') - @endFormGroup - - @formGroup('email') - - - @unless(Auth::user()->hasVerifiedEmail()) - - This email address is not verified yet. - Resend verification email. - - @endunless +
+
+
+ + +
- @error('email') - @endFormGroup +
+ + + {{ Auth::user()->bio() }} + + The user bio is limited to 160 characters. +
+
+
+ +
+ +
+
+
- @formGroup('username') - - - @error('username') - @endFormGroup +
+
+ + - @formGroup('twitter') - - - @error('twitter_handle') - @endFormGroup + @unless(Auth::user()->hasVerifiedEmail()) + + This email address is not verified yet. + Resend verification email. + + @endunless +
- @formGroup('bio') - - - The user bio is limited to 160 characters. - @error('bio') - @endFormGroup +
+ + +
-
- +
+ Twitter handle + + + Enter your Twitter handle without the leading @ symbol + +
+
+
-
-
- @unless (Auth::user()->isAdmin()) -
-

Danger Zone

-

Please be aware that deleting your account will also remove all of your data, including your threads and replies. This cannot be undone.

-
- Delete Account +
+ + + Update Profile + +
-
- @include('_partials._delete_modal', [ - 'identifier' => 'delete-user', - 'route' => ['settings.profile.delete'], - 'title' => 'Delete Account', - 'submit' => 'Confirm', - 'body' => '

Deleting your account will remove any related content like threads & replies. This cannot be undone.

', - ]) - @endunless -@endsection +
+ +
diff --git a/resources/views/users/settings/remove.blade.php b/resources/views/users/settings/remove.blade.php new file mode 100644 index 000000000..5f4a7d90f --- /dev/null +++ b/resources/views/users/settings/remove.blade.php @@ -0,0 +1,29 @@ +@unless (Auth::user()->isAdmin()) +
+
+
+
+

Danger Zone

+

+ Please be aware that deleting your account will also remove all of your data, including your threads and replies. This cannot be undone. +

+
+
+
+ + + Delete Account + + +
+
+
+ + @include('_partials._delete_modal', [ + 'identifier' => 'delete-user', + 'route' => ['settings.profile.delete'], + 'title' => 'Delete Account', + 'submit' => 'Confirm', + 'body' => '

Deleting your account will remove any related content like threads & replies. This cannot be undone.

', + ]) +@endunless \ No newline at end of file diff --git a/resources/views/users/settings/settings.blade.php b/resources/views/users/settings/settings.blade.php new file mode 100644 index 000000000..09d115946 --- /dev/null +++ b/resources/views/users/settings/settings.blade.php @@ -0,0 +1,25 @@ +@title('Settings') + +@extends('layouts.base', ['isTailwindUi' => true]) + +@section('body') +
+
+
+

Settings

+
+
+ + @include('layouts._alerts') + +
+
+
+ @include('users.settings.profile') + @include('users.settings.password') + @include('users.settings.remove') +
+
+
+
+@endsection diff --git a/resources/views/vendor/blade-ui-kit/components/forms/inputs/email.blade.php b/resources/views/vendor/blade-ui-kit/components/forms/inputs/email.blade.php new file mode 100644 index 000000000..ad6def82f --- /dev/null +++ b/resources/views/vendor/blade-ui-kit/components/forms/inputs/email.blade.php @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/resources/views/vendor/blade-ui-kit/components/forms/inputs/input.blade.php b/resources/views/vendor/blade-ui-kit/components/forms/inputs/input.blade.php new file mode 100644 index 000000000..fd5dde18b --- /dev/null +++ b/resources/views/vendor/blade-ui-kit/components/forms/inputs/input.blade.php @@ -0,0 +1,31 @@ +
+
+ @if ($attributes->get('prefix-icon')) +
+ @svg($attributes->get('prefix-icon'), ['class' => 'h-5 w-5 text-gray-400']) +
+ @endif + + merge([ + 'class' => 'form-input block w-full sm:text-sm sm:leading-5 mt-1' . ($attributes->get('prefix-icon') ? ' pl-10' : '') . ($errors->has($name) ? ' border-red-300 text-red-900 placeholder-red-300 focus:outline-none focus:ring-red-500 focus:border-red-500' : '') + ]) }} + /> + + @if ($errors->has($name)) +
+ +
+ @endif +
+ + @if ($errors->has($name)) + @foreach ($errors->get($name) as $error) +

{{ $error }}

+ @endforeach + @endif +
\ No newline at end of file diff --git a/resources/views/vendor/blade-ui-kit/components/forms/inputs/password.blade.php b/resources/views/vendor/blade-ui-kit/components/forms/inputs/password.blade.php new file mode 100644 index 000000000..32ab49cea --- /dev/null +++ b/resources/views/vendor/blade-ui-kit/components/forms/inputs/password.blade.php @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/resources/views/vendor/blade-ui-kit/components/forms/inputs/textarea.blade.php b/resources/views/vendor/blade-ui-kit/components/forms/inputs/textarea.blade.php new file mode 100644 index 000000000..d2ff5a481 --- /dev/null +++ b/resources/views/vendor/blade-ui-kit/components/forms/inputs/textarea.blade.php @@ -0,0 +1,22 @@ +
+ + + @if ($errors->has($name)) +
+ +
+ @endif + + @if ($errors->has($name)) + @foreach ($errors->get($name) as $error) +

{{ $error }}

+ @endforeach + @endif +
diff --git a/resources/views/vendor/blade-ui-kit/components/forms/label.blade.php b/resources/views/vendor/blade-ui-kit/components/forms/label.blade.php new file mode 100644 index 000000000..fff8dc4f0 --- /dev/null +++ b/resources/views/vendor/blade-ui-kit/components/forms/label.blade.php @@ -0,0 +1,3 @@ + diff --git a/routes/web.php b/routes/web.php index 71dfc011a..b5f779f04 100644 --- a/routes/web.php +++ b/routes/web.php @@ -73,7 +73,6 @@ Route::get('settings', [ProfileSettingsController::class, 'edit'])->name('settings.profile'); Route::put('settings', [ProfileSettingsController::class, 'update'])->name('settings.profile.update'); Route::delete('settings', [ProfileSettingsController::class, 'destroy'])->name('settings.profile.delete'); -Route::get('settings/password', [PasswordController::class, 'edit'])->name('settings.password'); Route::put('settings/password', [PasswordController::class, 'update'])->name('settings.password.update'); // Forum diff --git a/tests/Feature/SettingsTest.php b/tests/Feature/SettingsTest.php index 2d39fcabe..3823c5f0c 100644 --- a/tests/Feature/SettingsTest.php +++ b/tests/Feature/SettingsTest.php @@ -23,7 +23,7 @@ public function users_can_update_their_profile() $this->login(); $this->visit('/settings') - ->submitForm('Save', [ + ->submitForm('Update Profile', [ 'name' => 'Freek Murze', 'email' => 'freek@example.com', 'username' => 'freekmurze', @@ -46,7 +46,7 @@ public function users_cannot_choose_duplicate_usernames_or_email_addresses() $this->login(); $this->visit('/settings') - ->submitForm('Save', [ + ->submitForm('Update Profile', [ 'name' => 'Freek Murze', 'email' => 'freek@example.com', 'username' => 'freekmurze', @@ -82,13 +82,13 @@ public function users_can_update_their_password() { $this->login(); - $this->visit('/settings/password') - ->submitForm('Save', [ + $this->visit('/settings') + ->submitForm('Update Password', [ 'current_password' => 'password', 'password' => 'newpassword', 'password_confirmation' => 'newpassword', ]) - ->seePageIs('/settings/password') + ->seePageIs('/settings') ->see('Password successfully changed!'); $this->assertPasswordWasHashedAndSaved(); @@ -101,12 +101,12 @@ public function users_can_set_their_password_when_they_have_none_set_yet() $this->loginAs($user); - $this->visit('/settings/password') - ->submitForm('Save', [ + $this->visit('/settings') + ->submitForm('Update Password', [ 'password' => 'newpassword', 'password_confirmation' => 'newpassword', ]) - ->seePageIs('/settings/password') + ->seePageIs('/settings') ->see('Password successfully changed!'); $this->assertPasswordWasHashedAndSaved(); @@ -120,7 +120,7 @@ public function twitter_is_optional() $this->loginAs($user); $this->visit('/settings') - ->submitForm('Save', [ + ->submitForm('Update Profile', [ 'name' => 'Freek Murze', 'email' => 'freek@example.com', 'username' => 'freekmurze',