From 99ff11c4038168b2a7652d698e59c8aa12af54d4 Mon Sep 17 00:00:00 2001 From: Alexander Nikushkin Date: Mon, 17 Jun 2024 12:50:32 +0500 Subject: [PATCH 1/7] docs(advanced): "Submit" event --- .../pages/en/advanced/form_builder.blade.php | 27 +++++++++++++++++++ .../pages/ru/advanced/form_builder.blade.php | 27 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/resources/views/pages/en/advanced/form_builder.blade.php b/resources/views/pages/en/advanced/form_builder.blade.php index 5d0556dc..bc88bdbc 100644 --- a/resources/views/pages/en/advanced/form_builder.blade.php +++ b/resources/views/pages/en/advanced/form_builder.blade.php @@ -16,6 +16,7 @@ ['url' => '#apply', 'label' => 'Apply'], ['url' => '#method', 'label' => 'Calling methods'], ['url' => '#event', 'label' => 'Dispatch events'], + ['url' => '#submit', 'label' => '"Submit" event'], ] ]" > @@ -464,4 +465,30 @@ public function updateSomething(MoonShineRequest $request) ->dispatchEvent(JsEvent::OFF_CANVAS_TOGGLED, 'default'), // [tl! focus] +"Submit" event + + + To submit a form, you can call the Submit event. + + + +AlpineJs::event(JsEvent::FORM_SUBMIT, 'componentName') + + + + + +public function formButtons(): array +{ + return [ + ActionButton::make('Save')->dispatchEvent(AlpineJs::event(JsEvent::FORM_SUBMIT, $this->uriKey())) + ]; +} + + + + For more information about AlpineJs helpers, please refer to + Js events. + + diff --git a/resources/views/pages/ru/advanced/form_builder.blade.php b/resources/views/pages/ru/advanced/form_builder.blade.php index 7f418679..68dea31c 100644 --- a/resources/views/pages/ru/advanced/form_builder.blade.php +++ b/resources/views/pages/ru/advanced/form_builder.blade.php @@ -16,6 +16,7 @@ ['url' => '#apply', 'label' => 'Apply'], ['url' => '#method', 'label' => 'Вызов методов'], ['url' => '#event', 'label' => 'Вызов событий'], + ['url' => '#submit', 'label' => 'Событие "Submit"'], ] ]" > @@ -464,4 +465,30 @@ public function updateSomething(MoonShineRequest $request) ->dispatchEvent(JsEvent::OFF_CANVAS_TOGGLED, 'default'), // [tl! focus] +Событие "Submit" + + + Для отправки формы можно вызвать событие Submit. + + + +AlpineJs::event(JsEvent::FORM_SUBMIT, 'componentName') + + + + + +public function formButtons(): array +{ + return [ + ActionButton::make('Save')->dispatchEvent(AlpineJs::event(JsEvent::FORM_SUBMIT, $this->uriKey())) + ]; +} + + + + За более подробной информацией о помощниках AlpineJs обратитесь к разделу + Js events. + + From e130b8af0c95f8b65d84d21b0543b148f047c4ec Mon Sep 17 00:00:00 2001 From: Alexander Nikushkin Date: Mon, 17 Jun 2024 13:20:55 +0500 Subject: [PATCH 2/7] docs(advanced): enum JsEvent --- .../pages/en/advanced/js_events.blade.php | 21 +++++++++++++++++++ .../pages/ru/advanced/js_events.blade.php | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/resources/views/pages/en/advanced/js_events.blade.php b/resources/views/pages/en/advanced/js_events.blade.php index 12e5afc2..7eb7675f 100644 --- a/resources/views/pages/en/advanced/js_events.blade.php +++ b/resources/views/pages/en/advanced/js_events.blade.php @@ -2,6 +2,7 @@ 'Разделы' => [ ['url' => '#blade-directives', 'label' => 'Blade directives'], ['url' => '#helper', 'label' => 'AlpineJs helper'], + ['url' => '#default-events', 'label' => 'Default events'], ] ]"> @@ -105,4 +106,24 @@ ]); +Default events + + + There are several default events defined in the MoonShine admin panel, + the names of which can be conveniently obtained via enum JsEvent. + + + +
  • JsEvent::FRAGMENT_UPDATED - fragment update,
  • +
  • JsEvent::TABLE_UPDATED - table update,
  • +
  • JsEvent::TABLE_REINDEX - updating table indexes when sorting,
  • +
  • JsEvent::TABLE_ROW_UPDATED - updating a row in the table,
  • +
  • JsEvent::CARDS_UPDATED - updating the Cards list,
  • +
  • JsEvent::FORM_RESET - form reset,
  • +
  • JsEvent::FORM_SUBMIT - submitting the form,
  • +
  • JsEvent::MODAL_TOGGLED - opening / closing a modal window,
  • +
  • JsEvent::OFF_CANVAS_TOGGLED - opening / closing Offcanvas,
  • +
  • JsEvent::TOAST - call Toast.
  • +
    + diff --git a/resources/views/pages/ru/advanced/js_events.blade.php b/resources/views/pages/ru/advanced/js_events.blade.php index 5c293ea3..3894aac7 100644 --- a/resources/views/pages/ru/advanced/js_events.blade.php +++ b/resources/views/pages/ru/advanced/js_events.blade.php @@ -2,6 +2,7 @@ 'Разделы' => [ ['url' => '#blade-directives', 'label' => 'Blade-директивы'], ['url' => '#helper', 'label' => 'Помощник AlpineJs'], + ['url' => '#default-events', 'label' => 'События по умолчанию'], ] ]"> @@ -105,4 +106,24 @@ ]); +События по умолчанию + + + В админ-панели MoonShine определены несколько событий по умолчанию, + названия которых можно удобно получить через enum JsEvent. + + + +
  • JsEvent::FRAGMENT_UPDATED - обновление фрагмента,
  • +
  • JsEvent::TABLE_UPDATED - обновление таблицы,
  • +
  • JsEvent::TABLE_REINDEX - обновление индексов таблицы при сортировке,
  • +
  • JsEvent::TABLE_ROW_UPDATED - обновление строки в таблице,
  • +
  • JsEvent::CARDS_UPDATED - обновление списка Сards,
  • +
  • JsEvent::FORM_RESET - сброс формы,
  • +
  • JsEvent::FORM_SUBMIT - отправка формы,
  • +
  • JsEvent::MODAL_TOGGLED - открытие / закрытие модального окна,
  • +
  • JsEvent::OFF_CANVAS_TOGGLED - открытие / закрытие Offcanvas,
  • +
  • JsEvent::TOAST - вызов Toast.
  • +
    + From 08ff316c21221476ac904b8de8264427a79a71e6 Mon Sep 17 00:00:00 2001 From: Alexander Nikushkin Date: Mon, 17 Jun 2024 13:59:29 +0500 Subject: [PATCH 3/7] docs(fields): changeEditButton and withoutModals methods for HasMany field --- .../views/pages/en/fields/has_many.blade.php | 38 +++++++++++++++++++ .../views/pages/ru/fields/has_many.blade.php | 38 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/resources/views/pages/en/fields/has_many.blade.php b/resources/views/pages/en/fields/has_many.blade.php index 40e3ae0c..d3d8e756 100644 --- a/resources/views/pages/en/fields/has_many.blade.php +++ b/resources/views/pages/en/fields/has_many.blade.php @@ -8,6 +8,8 @@ ['url' => '#limit', 'label' => 'Number of records'], ['url' => '#only-link', 'label' => 'Link only'], ['url' => '#parent-id', 'label' => 'Parent ID'], + ['url' => '#change-edit-button', 'label' => 'Edit button'], + ['url' => '#without-modals', 'label' => 'Modal'], ['url' => '#modify', 'label' => 'Modify'], ['url' => '#advanced', 'label' => 'Advanced'], ] @@ -195,6 +197,42 @@ public function fields(): array @include('pages.en.fields.shared.parent_id') +Edit button + + + The changeEditButton() method allows you to completely redefine the edit button. + + + +use MoonShine\Fields\Relationships\HasMany; + +//... + +HasMany::make('Comments', 'comments', resource: new CommentResource()) + ->changeEditButton( + ActionButton::make( + 'Edit', + fn(Comment $comment) => (new CommentResource())->formPageUrl($comment) + ) + ) // [tl! focus:-5] + + +Modal + + + By default, creating and editing a HasMany field entry occurs in a modal, + The withoutModals() method allows you to disable this behavior. + + + +use MoonShine\Fields\Relationships\HasMany; + +//... + +HasMany::make('Comments', 'comments', resource: new CommentResource()) + ->withoutModals() // [tl! focus] + + Modify diff --git a/resources/views/pages/ru/fields/has_many.blade.php b/resources/views/pages/ru/fields/has_many.blade.php index f79764c8..28ca3bc5 100644 --- a/resources/views/pages/ru/fields/has_many.blade.php +++ b/resources/views/pages/ru/fields/has_many.blade.php @@ -8,6 +8,8 @@ ['url' => '#limit', 'label' => 'Количество записей'], ['url' => '#only-link', 'label' => 'Только ссылка'], ['url' => '#parent-id', 'label' => 'ID родителя'], + ['url' => '#change-edit-button', 'label' => 'Кнопка редактирования'], + ['url' => '#without-modals', 'label' => 'Модальные окна'], ['url' => '#modify', 'label' => 'Модификация'], ['url' => '#advanced', 'label' => 'Продвинутое применение'], ] @@ -195,6 +197,42 @@ public function fields(): array @include('pages.ru.fields.shared.parent_id') +Кнопка редактирования + + + Метод changeEditButton() позволяет полностью переопределить кнопку редактирования. + + + +use MoonShine\Fields\Relationships\HasMany; + +//... + +HasMany::make('Comments', 'comments', resource: new CommentResource()) + ->changeEditButton( + ActionButton::make( + 'Edit', + fn(Comment $comment) => (new CommentResource())->formPageUrl($comment) + ) + ) // [tl! focus:-5] + + +Модальные окна + + + По умолчанию создание и редактирование записи поля HasMany происходит в модальном окне, + метод withoutModals() позволяет отключить такое поведение. + + + +use MoonShine\Fields\Relationships\HasMany; + +//... + +HasMany::make('Comments', 'comments', resource: new CommentResource()) + ->withoutModals() // [tl! focus] + + Модификация From 8035b6ac9ecb6007b7a310a8c9425e686df6e2f9 Mon Sep 17 00:00:00 2001 From: Alexander Nikushkin Date: Mon, 17 Jun 2024 15:02:53 +0500 Subject: [PATCH 4/7] docs(advanced): events for MoonShineJsonResponse --- .../pages/en/advanced/js_events.blade.php | 29 +++++++++++++++++++ .../pages/ru/advanced/js_events.blade.php | 29 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/resources/views/pages/en/advanced/js_events.blade.php b/resources/views/pages/en/advanced/js_events.blade.php index 7eb7675f..c04b429d 100644 --- a/resources/views/pages/en/advanced/js_events.blade.php +++ b/resources/views/pages/en/advanced/js_events.blade.php @@ -3,6 +3,7 @@ ['url' => '#blade-directives', 'label' => 'Blade directives'], ['url' => '#helper', 'label' => 'AlpineJs helper'], ['url' => '#default-events', 'label' => 'Default events'], + ['url' => '#response-events', 'label' => 'Calling events via Response'], ] ]"> @@ -126,4 +127,32 @@
  • JsEvent::TOAST - call Toast.
  • +Calling events via Response + + + In MoonShine you can return events to MoonShineJsonResponse, which will then be called.
    + To do this, you need to use the events() method. +
    + + +events(array $events) + + + +
  • $events - array of events to be called.
  • +
    + + +use MoonShine\Enums\JsEvent; +use MoonShine\Http\Responses\MoonShineJsonResponse; +use MoonShine\Support\AlpineJs; + +//... + +return MoonShineJsonResponse::make() + ->events([ + AlpineJs::event(JsEvent::TABLE_UPDATED, 'index'), + ]); // [tl! focus:-2] + + diff --git a/resources/views/pages/ru/advanced/js_events.blade.php b/resources/views/pages/ru/advanced/js_events.blade.php index 3894aac7..e25d204e 100644 --- a/resources/views/pages/ru/advanced/js_events.blade.php +++ b/resources/views/pages/ru/advanced/js_events.blade.php @@ -3,6 +3,7 @@ ['url' => '#blade-directives', 'label' => 'Blade-директивы'], ['url' => '#helper', 'label' => 'Помощник AlpineJs'], ['url' => '#default-events', 'label' => 'События по умолчанию'], + ['url' => '#response-events', 'label' => 'Вызов событий через Response'], ] ]"> @@ -126,4 +127,32 @@
  • JsEvent::TOAST - вызов Toast.
  • +Вызов событий через Response + + + В MoonShine можно вернуть события в MoonShineJsonResponse, которые потом будут вызваны.
    + Для этого необходимо воспользоваться методом events(). +
    + + +events(array $events) + + + +
  • $events - массив вызываемых событий.
  • +
    + + +use MoonShine\Enums\JsEvent; +use MoonShine\Http\Responses\MoonShineJsonResponse; +use MoonShine\Support\AlpineJs; + +//... + +return MoonShineJsonResponse::make() + ->events([ + AlpineJs::event(JsEvent::TABLE_UPDATED, 'index'), + ]); // [tl! focus:-2] + + From 8864fe91658543166573e074a8ac056cb1847d1a Mon Sep 17 00:00:00 2001 From: Alexander Nikushkin Date: Mon, 17 Jun 2024 15:18:45 +0500 Subject: [PATCH 5/7] docs(menu): multi-level menu --- .../views/pages/en/advanced/menu.blade.php | 252 ------------------ resources/views/pages/en/menu.blade.php | 4 + .../views/pages/ru/advanced/menu.blade.php | 252 ------------------ resources/views/pages/ru/menu.blade.php | 4 + 4 files changed, 8 insertions(+), 504 deletions(-) delete mode 100644 resources/views/pages/en/advanced/menu.blade.php delete mode 100644 resources/views/pages/ru/advanced/menu.blade.php diff --git a/resources/views/pages/en/advanced/menu.blade.php b/resources/views/pages/en/advanced/menu.blade.php deleted file mode 100644 index 9c6993f7..00000000 --- a/resources/views/pages/en/advanced/menu.blade.php +++ /dev/null @@ -1,252 +0,0 @@ - - -Registration - - - In the resource study section, we have already figured out how to register sections of the admin panel, - after which they also appear in the menu. - - - -namespace App\Providers; - -use Illuminate\Support\ServiceProvider; -use MoonShine\Menu\MenuItem; // [tl! focus] -use MoonShine\MoonShine; // [tl! focus] -use MoonShine\Resources\MoonShineUserResource; -use MoonShine\Resources\MoonShineUserRoleResource; - -class MoonShineServiceProvider extends ServiceProvider -{ - //... - - public function boot() - { - app(MoonShine::class)->menu([ // [tl! focus:start] - MenuItem::make('Admins', new MoonShineUserResource()), - MenuItem::make('Roles', new MoonShineUserRoleResource()), - ]); // [tl! focus:end] - } -} - - - - But for the convenience of the interface, we can also group menu items. - - - -namespace App\Providers; - -use Illuminate\Support\ServiceProvider; -use MoonShine\Menu\MenuItem; -use MoonShine\Menu\MenuGroup; // [tl! focus] -use MoonShine\MoonShine; -use MoonShine\Resources\MoonShineUserResource; -use MoonShine\Resources\MoonShineUserRoleResource; - -class MoonShineServiceProvider extends ServiceProvider -{ - //... - - public function boot() - { - app(MoonShine::class)->menu([ - MenuGroup::make('System', [ // [tl! focus] - MenuItem::make('Admins', new MoonShineUserResource()), - MenuItem::make('Roles', new MoonShineUserRoleResource()), - ]) // [tl! focus] - ]); - } -} - - - - You just need to add resources as the second parameter to the MoonShine\Menu\MenuGroup class. - Well, the first parameter is the name of the group! - - - - - -Display condition - - - Display menus based on condition. - - - -//... -app(MoonShine::class)->menu([ - MenuGroup::make('System', [ - MenuItem::make('Admins', new MoonShineUserResource()), - MenuItem::make('Roles', new MoonShineUserRoleResource()), - ])->canSee(function(Request $request) { // [tl! focus:start] - return $request->user('moonshine')?->id === 1; - }) // [tl! focus:end] -]); -//... - - -External reference - - - Ability to add a custom link: - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Laravel Documentation', 'https://laravel.com') // [tl! focus] -]); -//... - - - - Links can be passed through the function. - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Admins', function () { // [tl! focus:start] - return (new MoonShineUserResource())->indexPageUrl(); - }), - MenuItem::make('Home', fn() => route('home')) // [tl! focus:end] -]); -//... - - -Icon - - - It is also possible to change the icon of a menu item. - - - -//... -app(MoonShine::class)->menu([ - MenuGroup::make('System', [ // [tl! focus:start] - MenuItem::make('Admins', new MoonShineUserResource())->icon('heroicons.hashtag'), - MenuItem::make('Roles', new MoonShineUserRoleResource())->icon('heroicons.hashtag'), - ])->icon('app') // [tl! focus:end] - // or - MenuGroup::make('Blog', [ // [tl! focus:start] - MenuItem::make('Comments', new CommentResource(), 'heroicons.chat-bubble-left') - ], 'heroicons.newspaper') // [tl! focus:end] -]); -//... - - - - For more detailed information, please refer to the section Icons. - - -Label - - - It is also possible to add a counter to a menu item. - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Comments', new CommentResource()) - ->badge(fn() => Comment::query()->count()), // [tl! focus] -]); -//... - - - - - -Translation - - - To translate menu items, you need to pass the translation key as the name - and add the translatable() method. - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('menu.Comments', new CommentResource()) - ->translatable() // [tl! focus] - // or - MenuItem::make('Comments', new CommentResource()) - ->translatable('menu') // [tl! focus] -]); -//... - - - -// lang/ru/menu.php - -return [ - 'Comments' => 'Comments', -]; - - - - You can use Laravel's translation tools to translate menu labels. - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Comments', new CommentResource()) - ->badge(fn() => __('menu.badge.new')) // [tl! focus] -]); -//... - - -Delimiter - - - Menu items can be visually divided using MenuDivider - - - -use MoonShine\Menu\MenuDivider; // [tl! focus] - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Categories', new CategoryResource()), - MenuDivider::make(), // [tl! focus] - MenuItem::make('Articles', new ArticleResource()), -]); -//... - - - - - - - You can use text as a separator. To do this, you need to pass it to the make() method. - - - -use MoonShine\Menu\MenuDivider; // [tl! focus] - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Categories', new CategoryResource()), - MenuDivider::make('Divider'), // [tl! focus] - MenuItem::make('Articles', new ArticleResource()), -]); -//... - - - - - - diff --git a/resources/views/pages/en/menu.blade.php b/resources/views/pages/en/menu.blade.php index 6b161f57..344239b2 100644 --- a/resources/views/pages/en/menu.blade.php +++ b/resources/views/pages/en/menu.blade.php @@ -191,6 +191,10 @@ protected function menu(): array } + + To create a multi-level menu, groups can be nested. + + Delimiter diff --git a/resources/views/pages/ru/advanced/menu.blade.php b/resources/views/pages/ru/advanced/menu.blade.php deleted file mode 100644 index e6142311..00000000 --- a/resources/views/pages/ru/advanced/menu.blade.php +++ /dev/null @@ -1,252 +0,0 @@ - - -Регистрация - - - В разделе изучения ресурсов мы уже разобрались как регистрировать разделы админ-панели, - после чего они также появляются в меню. - - - -namespace App\Providers; - -use Illuminate\Support\ServiceProvider; -use MoonShine\Menu\MenuItem; // [tl! focus] -use MoonShine\MoonShine; // [tl! focus] -use MoonShine\Resources\MoonShineUserResource; -use MoonShine\Resources\MoonShineUserRoleResource; - -class MoonShineServiceProvider extends ServiceProvider -{ - //... - - public function boot() - { - app(MoonShine::class)->menu([ // [tl! focus:start] - MenuItem::make('Admins', new MoonShineUserResource()), - MenuItem::make('Roles', new MoonShineUserRoleResource()), - ]); // [tl! focus:end] - } -} - - - - Но для удобства интерфейса мы также можем сгруппировать пункты меню. - - - -namespace App\Providers; - -use Illuminate\Support\ServiceProvider; -use MoonShine\Menu\MenuItem; -use MoonShine\Menu\MenuGroup; // [tl! focus] -use MoonShine\MoonShine; -use MoonShine\Resources\MoonShineUserResource; -use MoonShine\Resources\MoonShineUserRoleResource; - -class MoonShineServiceProvider extends ServiceProvider -{ - //... - - public function boot() - { - app(MoonShine::class)->menu([ - MenuGroup::make('System', [ // [tl! focus] - MenuItem::make('Admins', new MoonShineUserResource()), - MenuItem::make('Roles', new MoonShineUserRoleResource()), - ]) // [tl! focus] - ]); - } -} - - - - Всего лишь необходимо добавить ресурсы вторым параметром в класс MoonShine\Menu\MenuGroup. - Ну а первый параметр это название группы! - - - - - -Условие отображения - - - Отображать меню по условию. - - - -//... -app(MoonShine::class)->menu([ - MenuGroup::make('System', [ - MenuItem::make('Admins', new MoonShineUserResource()), - MenuItem::make('Roles', new MoonShineUserRoleResource()), - ])->canSee(function(Request $request) { // [tl! focus:start] - return $request->user('moonshine')?->id === 1; - }) // [tl! focus:end] -]); -//... - - -Внешняя ссылка - - - Возможность добавить кастомный линк: - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Документация Laravel', 'https://laravel.com') // [tl! focus] -]); -//... - - - - Ссылки можно передавать через функцию. - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Admins', function () { // [tl! focus:start] - return (new MoonShineUserResource())->indexPageUrl(); - }), - MenuItem::make('Home', fn() => route('home')) // [tl! focus:end] -]); -//... - - -Иконка - - - Также есть возможность менять иконку у пункта меню. - - - -//... -app(MoonShine::class)->menu([ - MenuGroup::make('Система', [ // [tl! focus:start] - MenuItem::make('Admins', new MoonShineUserResource())->icon('heroicons.hashtag'), - MenuItem::make('Roles', new MoonShineUserRoleResource())->icon('heroicons.hashtag'), - ])->icon('app') // [tl! focus:end] - // or - MenuGroup::make('Blog', [ // [tl! focus:start] - MenuItem::make('Comments', new CommentResource(), 'heroicons.chat-bubble-left') - ], 'heroicons.newspaper') // [tl! focus:end] -]); -//... - - - - За более подробной информацией обратитесь к разделу Icons. - - -Метка - - - Также есть возможность добавить счетчик к пункту меню. - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Comments', new CommentResource()) - ->badge(fn() => Comment::query()->count()), // [tl! focus] -]); -//... - - - - - -Перевод - - - Для перевода пунктов меню необходимо в качестве названия передать ключ перевода - и добавить метод translatable(). - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('menu.Comments', new CommentResource()) - ->translatable() // [tl! focus] - // or - MenuItem::make('Comments', new CommentResource()) - ->translatable('menu') // [tl! focus] -]); -//... - - - -// lang/ru/menu.php - -return [ - 'Comments' => 'Комментарии', -]; - - - - Для перевода меток меню можно воспользоваться средствами перевода Laravel. - - - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Comments', new CommentResource()) - ->badge(fn() => __('menu.badge.new')) // [tl! focus] -]); -//... - - -Разделитель - - - Пункты меню можно визуально разделить с помощью MenuDivider - - - -use MoonShine\Menu\MenuDivider; // [tl! focus] - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Categories', new CategoryResource()), - MenuDivider::make(), // [tl! focus] - MenuItem::make('Articles', new ArticleResource()), -]); -//... - - - - - - - В качестве разделителя можно использовать текст. Для этого его нужно передать методу make(). - - - -use MoonShine\Menu\MenuDivider; // [tl! focus] - -//... -app(MoonShine::class)->menu([ - MenuItem::make('Categories', new CategoryResource()), - MenuDivider::make('Divider'), // [tl! focus] - MenuItem::make('Articles', new ArticleResource()), -]); -//... - - - - - - diff --git a/resources/views/pages/ru/menu.blade.php b/resources/views/pages/ru/menu.blade.php index 2cf255c4..56f89c4e 100644 --- a/resources/views/pages/ru/menu.blade.php +++ b/resources/views/pages/ru/menu.blade.php @@ -192,6 +192,10 @@ protected function menu(): array } + + Для создания многоуровнего меню, группы можно делать вложенными. + + Разделитель From 78a63e559da480a5abfd6f2b53a58704d28f79d8 Mon Sep 17 00:00:00 2001 From: Alexander Nikushkin Date: Mon, 17 Jun 2024 17:40:15 +0500 Subject: [PATCH 6/7] docs(recipes): saving images in a linked table --- resources/views/pages/en/recipes.blade.php | 4 +- .../recipes/images-in-linked-table.blade.php | 54 +++++++++++++++++++ resources/views/pages/ru/recipes.blade.php | 4 +- .../recipes/images-in-linked-table.blade.php | 54 +++++++++++++++++++ 4 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 resources/views/pages/en/recipes/images-in-linked-table.blade.php create mode 100644 resources/views/pages/ru/recipes/images-in-linked-table.blade.php diff --git a/resources/views/pages/en/recipes.blade.php b/resources/views/pages/en/recipes.blade.php index 98e3e16b..96559173 100644 --- a/resources/views/pages/en/recipes.blade.php +++ b/resources/views/pages/en/recipes.blade.php @@ -14,6 +14,7 @@ ['url' => '#hasmany-parent-id', 'label' => 'Parent ID in HasMany'], ['url' => '#tinymce-limit-preview', 'label' => 'TinyMce number of characters in preview'], ['url' => '#change-field-logic', 'label' => 'Changing field logic'], + ['url' => '#images-in-linked-table', 'label' => 'Saving images in a linked table'], ] ]" > @@ -30,7 +31,8 @@ @include('pages.en.recipes.hasmany-parent-id', ['title' => 'Parent ID in HasMany']) @include('pages.en.recipes.tinymce-limit-preview', ['title' => 'TinyMce number of characters in preview']) @include('pages.en.recipes.change-field-logic', [ - 'title' => 'An example of changing the behavior logic of the Image field to save paths to images in a separate database table.' + 'title' => 'Changing the behavior logic of the Image field to save paths to images in a separate database table' ]) +@include('pages.en.recipes.images-in-linked-table', ['title' => 'Saving images in a linked table']) diff --git a/resources/views/pages/en/recipes/images-in-linked-table.blade.php b/resources/views/pages/en/recipes/images-in-linked-table.blade.php new file mode 100644 index 00000000..f87719ab --- /dev/null +++ b/resources/views/pages/en/recipes/images-in-linked-table.blade.php @@ -0,0 +1,54 @@ + + + +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Storage; +use MoonShine\Fields\Image; + +// ... + +Image::make('Images', 'images') + ->multiple() + ->removable() + ->changeFill(function (Model $data, Image $field) { + // return $data->images->pluck('file'); + // or raw + return DB::table('images')->pluck('file'); + }) + ->onApply(function (Model $data) { + // block onApply + return $data; + }) + ->onAfterApply(function (Model $data, false|array $values, Image $field) { + // $field->getRemainingValues(); values that remained in the form taking into account deletions + // $field->toValue(); current images + // $field->toValue()->diff($field->getRemainingValues()) deleted images + + if($values !== false) { + foreach ($values as $value) { + DB::table('images')->insert([ + 'file' => $field->store($value), + ]); + } + } + + foreach ($field->toValue()->diff($field->getRemainingValues()) as $removed) { + DB::table('images')->where('file', $removed)->delete(); + Storage::disk('public')->delete($removed); + } + + // or $field->removeExcludedFiles(); + + return $data; + }) + ->onAfterDestroy(function (Model $data, mixed $values, Image $field) { + foreach ($values as $value) { + Storage::disk('public')->delete($value); + } + + return $data; + }) + + + diff --git a/resources/views/pages/ru/recipes.blade.php b/resources/views/pages/ru/recipes.blade.php index 36129f87..16979b35 100644 --- a/resources/views/pages/ru/recipes.blade.php +++ b/resources/views/pages/ru/recipes.blade.php @@ -14,6 +14,7 @@ ['url' => '#hasmany-parent-id', 'label' => 'ID родителя в HasMany'], ['url' => '#tinymce-limit-preview', 'label' => 'TinyMce количество символов в привью'], ['url' => '#change-field-logic', 'label' => 'Изменение логики поля'], + ['url' => '#images-in-linked-table', 'label' => 'Сохранение изображений в связанной таблице'], ] ]" > @@ -30,7 +31,8 @@ @include('pages.ru.recipes.hasmany-parent-id', ['title' => 'ID родителя в HasMany']) @include('pages.ru.recipes.tinymce-limit-preview', ['title' => 'TinyMce количество символов в привью']) @include('pages.ru.recipes.change-field-logic', [ - 'title' => 'Пример изменения логики поведения поля Image для сохранения путей к изображениям в отдельной таблице базы данных.' + 'title' => 'Изменение логики поведения поля Image для сохранения путей к изображениям в отдельной таблице базы данных' ]) +@include('pages.ru.recipes.images-in-linked-table', ['title' => 'Сохранение изображений в связанной таблице']) diff --git a/resources/views/pages/ru/recipes/images-in-linked-table.blade.php b/resources/views/pages/ru/recipes/images-in-linked-table.blade.php new file mode 100644 index 00000000..600f67eb --- /dev/null +++ b/resources/views/pages/ru/recipes/images-in-linked-table.blade.php @@ -0,0 +1,54 @@ + + + +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Storage; +use MoonShine\Fields\Image; + +// ... + +Image::make('Images', 'images') + ->multiple() + ->removable() + ->changeFill(function (Model $data, Image $field) { + // return $data->images->pluck('file'); + // or raw + return DB::table('images')->pluck('file'); + }) + ->onApply(function (Model $data) { + // block onApply + return $data; + }) + ->onAfterApply(function (Model $data, false|array $values, Image $field) { + // $field->getRemainingValues(); values that remained in the form taking into account deletions + // $field->toValue(); current images + // $field->toValue()->diff($field->getRemainingValues()) deleted images + + if($values !== false) { + foreach ($values as $value) { + DB::table('images')->insert([ + 'file' => $field->store($value), + ]); + } + } + + foreach ($field->toValue()->diff($field->getRemainingValues()) as $removed) { + DB::table('images')->where('file', $removed)->delete(); + Storage::disk('public')->delete($removed); + } + + // or $field->removeExcludedFiles(); + + return $data; + }) + ->onAfterDestroy(function (Model $data, mixed $values, Image $field) { + foreach ($values as $value) { + Storage::disk('public')->delete($value); + } + + return $data; + }) + + + From f22c65569f81a8ab2f371af885b90144eabee265 Mon Sep 17 00:00:00 2001 From: Alexander Nikushkin Date: Mon, 17 Jun 2024 17:45:05 +0500 Subject: [PATCH 7/7] docs(fields): helper methods for File field --- .../views/pages/en/fields/file.blade.php | 29 +++++++++++++++++++ .../views/pages/ru/fields/file.blade.php | 29 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/resources/views/pages/en/fields/file.blade.php b/resources/views/pages/en/fields/file.blade.php index 3afc6dc9..6f5ffaa2 100644 --- a/resources/views/pages/en/fields/file.blade.php +++ b/resources/views/pages/en/fields/file.blade.php @@ -13,6 +13,7 @@ ['url' => '#customname', 'label' => 'Custom file name'], ['url' => '#names', 'label' => 'Element names'], ['url' => '#item-attributes', 'label' => 'Item attributes'], + ['url' => '#helper-methods', 'label' => 'Helper methods'], ] ]" > @@ -430,4 +431,32 @@ public function fields(): array //... +Helper methods + + + + + The getRemainingValues() method allows you to get the values that remained in the form, + taking into account the deletion. + + + +getRemainingValues() + + + + + + The removeExcludedFiles() method allows you to physically remove files during the process. + + + +removeExcludedFiles() + + + + Recipe: saving images + in the linked table. + + diff --git a/resources/views/pages/ru/fields/file.blade.php b/resources/views/pages/ru/fields/file.blade.php index d71b79b4..ad645610 100644 --- a/resources/views/pages/ru/fields/file.blade.php +++ b/resources/views/pages/ru/fields/file.blade.php @@ -13,6 +13,7 @@ ['url' => '#customname', 'label' => 'Произвольное имя файла'], ['url' => '#names', 'label' => 'Названия элементов'], ['url' => '#item-attributes', 'label' => 'Атрибуты элементов'], + ['url' => '#helper-methods', 'label' => 'Вспомогательные методы'], ] ]" > @@ -430,4 +431,32 @@ public function fields(): array //... +Вспомогательные методы + + + + + Метод getRemainingValues() позволяет получить значения + которые остались в форме с учетом удаления. + + + +getRemainingValues() + + + + + + Метод removeExcludedFiles() позволяет физически удалить файлы в процессе. + + + +removeExcludedFiles() + + + + Рецепт: сохранение изображений + в связанной таблице. + +