MoonShine — это админ-панель для Laravel, которая помогает быстро запускать MVP, внутренние кабинеты, CRM и CMS. Ниже — пошаговая инструкция по установке и первичной настройке.
1. Установка
Laravel
Убедитесь, что у вас установлен Laravel 10.48+. Подробнее в документации Laravel.
composer global require laravel/installerlaravel new example-appcd example-appcomposer global require laravel/installerlaravel new example-appcd example-app
MoonShine
composer require moonshine/moonshinecomposer require moonshine/moonshine
Starter kit
Если у вас уже установлен laravel/installer, то вы можете установить Laravel + MoonShine одной командой:
laravel new example-app --using=moonshine/applaravel new example-app --using=moonshine/app
2. Настройка
php artisan moonshine:install -Qphp artisan moonshine:install -Q
Создайте первого администратора. Введите e-mail (логин), имя и пароль — эти данные будут использоваться для входа.

3. Запуск проекта
Запустите локальный сервер:
php artisan servephp artisan serve
Откройте в браузере: http://127.0.0.1:8000/admin
Войдите под учётной записью администратора.
4. Создание первого ресурса
Сгенерируйте ресурс для модели (например, User):
php artisan moonshine:resource Userphp artisan moonshine:resource User
Готово! Теперь раздел Users доступен в админке.
http://127.0.0.1:8000/admin/resource/user-resource/user-index-page
Также вы найдёте его в меню.

5. Настройка ресурса
Раздел добавлен, но если открыть страницу создания записей, вы увидите пустую страницу без полей формы. Далее мы это исправим.
При создании ресурса так же были созданы 3 CRUD-страницы: UserIndexPage, UserFormPage и UserDetailPage.
Начнём с UserFormPage.
Воспользуемся полями Text, Email, Password и компонентами для лучшей структуры и сразу добавим валидацию.
class UserFormPage extends FormPage{protected function fields(): iterable{return [Grid::make([Column::make([Box::make('Contact information', [ID::make(),Text::make('Name'),Email::make('E-mail', 'email'),]),LineBreak::make(),Box::make('Change password', [Password::make('Password')->customAttributes(['autocomplete' => 'new-password']),PasswordRepeat::make('Password repeat')->customAttributes(['autocomplete' => 'confirm-password']),]),]),]),];}protected function rules(DataWrapperContract $item): array{return ['name' => 'required','email' => ['sometimes','bail','required','email',Rule::unique('users', 'email')->ignore($item->id),],'password' => !$item->exists? 'required|min:6|required_with:password_repeat|same:password_repeat': 'sometimes|nullable|min:6|required_with:password_repeat|same:password_repeat',];}}class UserFormPage extends FormPage{protected function fields(): iterable{return [Grid::make([Column::make([Box::make('Contact information', [ID::make(),Text::make('Name'),Email::make('E-mail', 'email'),]),LineBreak::make(),Box::make('Change password', [Password::make('Password')->customAttributes(['autocomplete' => 'new-password']),PasswordRepeat::make('Password repeat')->customAttributes(['autocomplete' => 'confirm-password']),]),]),]),];}protected function rules(DataWrapperContract $item): array{return ['name' => 'required','email' => ['sometimes','bail','required','email',Rule::unique('users', 'email')->ignore($item->id),],'password' => !$item->exists? 'required|min:6|required_with:password_repeat|same:password_repeat': 'sometimes|nullable|min:6|required_with:password_repeat|same:password_repeat',];}}
Далее наполним страницу UserIndexPage, на которой выводится список записей.
Дополнительно добавим фильтрацию и применим некоторые модификации индексной таблицы.
class UserIndexPage extends IndexPage{protected bool $isLazy = true;protected function fields(): iterable{return [ID::make()->sortable(),Text::make('Name'),Email::make('E-mail', 'email'),];}protected function filters(): iterable{return [Text::make('Name'),];}protected function modifyListComponent(ComponentContract $component): ComponentContract{return $component->columnSelection()->sticky()->stickyButtons();}}class UserIndexPage extends IndexPage{protected bool $isLazy = true;protected function fields(): iterable{return [ID::make()->sortable(),Text::make('Name'),Email::make('E-mail', 'email'),];}protected function filters(): iterable{return [Text::make('Name'),];}protected function modifyListComponent(ComponentContract $component): ComponentContract{return $component->columnSelection()->sticky()->stickyButtons();}}
Теперь давайте наполним раздел UserDetailPage для просмотра детальной информации об одной записи.
class UserDetailPage extends DetailPage{protected function fields(): iterable{return [ID::make(),Text::make('Name'),Email::make('E-mail', 'email'),];}}class UserDetailPage extends DetailPage{protected function fields(): iterable{return [ID::make(),Text::make('Name'),Email::make('E-mail', 'email'),];}}
Изменим заголовок раздела, добавив метод getTitle() для удобства локализации в будущем.
public function getTitle(): string{return __('Clients');}public function getTitle(): string{return __('Clients');}
Также рекомендуется указать $column, чтобы изменить отображаемое поле при связях. Вместо id укажем email.
protected string $column = 'email';protected string $column = 'email';
6. Брендирование
Настроим логотип и цветовую схему в App\Providers\MoonShineServiceProvider.php.
$config->logo('/images/logo.png')->logo('/images/logo-mini.png', small: true);$colors->primary('#2563EB')->secondary('#93C5FD');$config->logo('/images/logo.png')->logo('/images/logo-mini.png', small: true);$colors->primary('#2563EB')->secondary('#93C5FD');
6. Локализация
Настройка локализации в config/moonshine.php:
'locale' => 'ru','locales' => ['en','ru'],'locale' => 'ru','locales' => ['en','ru'],
Языковые файлы должны находиться в "/lang/vendor/moonshine". Их можно найти в разделе Плагины или сделать самостоятельно.
8. Документация
Мы установили MoonShine, настроили ресурс, добавили поля, фильтры, брендирование и локализацию.
Рекомендуем изучить документацию, рецепты и видео-гайды, чтобы использовать все возможности платформы.
Важные разделы:
Спасибо, что выбрали MoonShine!