admin panel created

This commit is contained in:
Thekindbull 2025-04-09 09:47:12 +08:00
parent 2c5dcebc84
commit 30f124a429
52 changed files with 2132 additions and 492 deletions

View File

@ -0,0 +1,100 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
class CreateModelAndMigrationCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'module:create {name}
{--momi=}
{--create_model=}
{--create_migration=}
{--add_migration=}
';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle()
{
if ($this->option('momi')) {
$this->input->setOption('create_model', $this->option('momi'));
$this->input->setOption('create_migration', $this->option('momi'));
}
if ($this->option('create_model')) {
$this->createModel();
}
if ($this->option('create_migration')) {
$this->createMigration();
}
if ($this->option('add_migration')) {
$this->addMigration();
}
}
private function createModel()
{
try
{
$path = trim($this->argument('name'));
$model = Str::singular(class_basename($this->option('create_model')));
$this->call('make:model', [
'name' => 'App\\Modules\\' . $path . '\\Models\\' . $model
]);
}
catch (\Exception $e)
{
$e->getMessage();
}
}
private function createMigration()
{
$path = trim($this->argument('name'));
$table = Str::plural(Str::snake(class_basename($this->option('create_migration'))));
try
{
$this->call('make:migration', [
'name' => 'create_' . $table . '_table',
'--create' => $table,
'--path' => 'app/Modules/' . $path . '/Database/Migrations'
]);
}
catch (\Exception $e)
{
$e->getMessage();
}
}
private function addMigration()
{
$path = trim($this->argument('name'));
$table = $this->option('add_migration');
try
{
$this->call('make:migration', [
'name' => $table,
'--path' => 'app/Modules/' . $path . '/Database/Migrations'
]);
}
catch (\Exception $e)
{
$e->getMessage();
}
}
}

View File

@ -0,0 +1,389 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class CreateModuleCommand extends Command
{
protected $files;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'make:module {name}
{--all : Create ready module}
';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Module creation command';
/**
* Create a new command instance
*
* @return void
*/
public function __construct(Filesystem $files)
{
parent::__construct();
$this->files = $files;
}
/**
* Execute the console command.
*/
public function handle()
{
if ($this->option('all'))
{
$directory = $this->getDirectory($this->argument('name'));
if ($this->files->isDirectory($directory))
{
$this->error('Module already exists!');
}
else
{
$this->createProviders();
$this->createConfig();
$this->createModel();
$this->createMigration();
$this->createController();
$this->createView();
}
}
}
private function getDirectory($directory)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $directory);
}
private function createModel()
{
try
{
$model = Str::singular(class_basename($this->argument('name')));
$this->call('make:model', [
'name' => 'App\\Modules\\' . trim($this->argument('name')) . '\\Models\\' . $model
]);
}
catch (\Exception $e)
{
$e->getMessage();
}
}
private function createView()
{
$directoryName = Str::singular(Str::studly(class_basename($this->argument('name'))));
$path = $this->getViewsPath($this->argument('name'));
if ($this->alreadyExists($path))
{
$this->error('View already exists!');
}
else
{
$this->makeDirectory($path);
$stub = $this->files->get(base_path('resources/stubs/view.stub'));
$this->files->put($path, $stub);
$this->info('Views created');
//livewire
$path = $this->getLivewireViewsPath($this->argument('name'));
$this->makeDirectory($path);
$this->info('Views - livewire folder created');
//components
$path = $this->getComponentsViewsPath($this->argument('name'));
$this->makeDirectory($path);
$this->info('Views - components folder created');
}
}
private function getViewsPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Views/index.blade.php';
}
private function getLivewireViewsPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Views/livewire/example.php';
}
private function getComponentsViewsPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Views/components/example.php';
}
private function createConfig()
{
$directoryName = Str::singular(Str::studly(class_basename($this->argument('name'))));
$path = $this->getConfigPath($this->argument('name'));
if ($this->alreadyExists($path))
{
$this->error('Config already exists!');
}
else
{
$this->makeDirectory($path);
$stub = $this->files->get(base_path('resources/stubs/config.stub'));
$this->files->put($path, $stub);
$this->info('Config created');
}
}
private function getConfigPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Config/config.php';
}
private function createProviders()
{
//Create ModuleServiceProvider
$directoryName = Str::singular(Str::studly(class_basename($this->argument('name'))));
$path = $this->getModuleServiceProviderPath($this->argument('name'));
if ($this->alreadyExists($path))
{
$this->error('ModuleServiceProvider already exists!');
}
else
{
$this->makeDirectory($path);
$stub = $this->files->get(base_path('resources/stubs/module_service_provider.stub'));
$stub = str_replace(
[
'TeamplateDirectoryName',
],
[
$directoryName
],
$stub
);
$this->files->put($path, $stub);
$this->info('ModuleServiceProvider created');
}
//Create RouteServiceProvider
$path = $this->getRouteServiceProviderPath($this->argument('name'));
if ($this->alreadyExists($path))
{
$this->error('RouteServiceProvider already exists!');
}
else
{
$this->makeDirectory($path);
$stub = $this->files->get(base_path('resources/stubs/route_service_provider.stub'));
$stub = str_replace(
[
'TeamplateDirectoryName',
],
[
$directoryName
],
$stub
);
$this->files->put($path, $stub);
$this->info('RouteServiceProvider created');
}
}
private function getModuleServiceProviderPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Providers/ModuleServiceProvider.php';
}
private function getRouteServiceProviderPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Providers/RouteServiceProvider.php';
}
private function createController()
{
$controller = Str::studly(class_basename($this->argument('name')));
$modelName = Str::singular(Str::studly(class_basename($this->argument('name'))));
$path = $this->getControllerPath($this->argument('name'));
if ($this->alreadyExists($path))
{
$this->error('Controller already exists!');
}
else
{
$this->makeDirectory($path);
$stub = $this->files->get(base_path('resources/stubs/controller.model.stub'));
$stub = str_replace(
[
'TeamplateNamespace',
'TeamplateFullModelClass',
'TeamplateClass',
'TeamplateDirectoryName'
],
[
'Modules\\' . trim($this->argument('name')) . '\\Http\\Controllers',
'Modules\\' . trim($this->argument('name')) . '\\Models\\' . $modelName,
$controller . 'Controller',
lcfirst($controller)
],
$stub
);
$this->files->put($path, $stub);
$this->info('Controller created');
//Livewire Http
$path = $this->getLivewireHttpPath($this->argument('name'));
$this->makeDirectory($path);
$this->info('Http - Livewire folder created');
//Components Http
$path = $this->getComponentsHttpPath($this->argument('name'));
$this->makeDirectory($path);
$this->info('Http - Components folder created');
//Policies Http
$path = $this->getPoliciesHttpPath($this->argument('name'));
$this->makeDirectory($path);
$this->info('Http - Policies folder created');
//Requests Http
$path = $this->getRequestsHttpPath($this->argument('name'));
$this->makeDirectory($path);
$this->info('Http - Requests folder created');
//Routes create
$this->createRoutes($controller, $modelName);
}
}
private function getLivewireHttpPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Http/Livewire/example.php';
}
private function getComponentsHttpPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Http/Components/example.php';
}
private function getPoliciesHttpPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Http/Policies/example.php';
}
private function getRequestsHttpPath($argument)
{
return $this->laravel['path'] .
'/Modules/' . str_replace('\\', '/', $argument) . '/Http/Requests/example.php';
}
private function createRoutes($controller, $modelName)
{
$routePath = $this->getRoutesPath($this->argument('name'));
if ($this->alreadyExists($routePath))
{
$this->error('Routes already exists!');
}
else
{
$this->makeDirectory($routePath);
$stub = $this->files->get(base_path('resources/stubs/routes.web.stub'));
$stub = str_replace(
[
'TeamplateDirectoryName',
'TeamplateRoutePrefix',
'TeamplateClass'
],
[
$controller,
lcfirst($modelName),
$controller . 'Controller'
],
$stub
);
$this->files->put($routePath, $stub);
$this->info('Routes created successfully');
}
}
private function alreadyExists($valuePath)
{
return $this->files->exists($valuePath);
}
private function getRoutesPath($argument)
{
return $this->laravel['path'] .
'/Modules/' .
str_replace('\\', '/', $argument) .
'/Routes/web.php';
}
private function getControllerPath($argument)
{
$controller = Str::studly(class_basename($argument));
return $this->laravel['path'] .
'/Modules/' .
str_replace('\\', '/', $argument) .
'/Http/Controllers/' .
$controller .
'Controller.php';
}
private function makeDirectory($path)
{
$this->files->makeDirectory(dirname($path), 0777, true, true);
//$this->files->makeDirectory(dirname($path));
}
private function createMigration()
{
$name = trim($this->argument('name'));
$table = Str::plural(Str::snake(class_basename($this->argument('name'))));
try
{
$this->call('make:migration', [
'name' => 'create_' . $table . '_table',
'--create' => $table,
'--path' => 'app/Modules/' . $name . '/Database/Migrations'
]);
}
catch (\Exception $e)
{
$e->getMessage();
}
}
}

View File

@ -0,0 +1,5 @@
<?php
return [
];

View File

@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
/*Schema::create('admins', function (Blueprint $table) {
$table->id();
$table->timestamps();
});*/
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('admins');
}
};

View File

@ -0,0 +1,68 @@
<?php
namespace Modules\Admin\Http\Controllers;
use Modules\Admin\Models\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User\UserRole;
use App\Models\User\Role;
use App\Models\User;
class AdminController extends Controller
{
public function index()
{
if (!$this->superAdminExists())
{
return $this->goToSuperAdminCreator();
}
return view('admin::index');
}
public function superAdminExists()
{
$count = UserRole::where('role_id', Role::SUPER_ADMIN)->count();
if ($count == 0)
{
return false;
}
return true;
}
public function goToSuperAdminCreator()
{
return view('admin::setAdmin.index', [
'users' => User::orderBy('name')->get()
]);
}
public function setSuperAdmin(Request $request)
{
if (!$this->superAdminExists())
{
$userId = false;
$user = User::where('email', $request->email)->orWhere('phone', $request->phone);
if ($user->count() == 1)
{
$user = $user->first();
$userId = $user->id;
}
elseif ($user->count() > 1)
{
return to_route('admin.index');
}
else
{
$user = User::create($request->all());
$userId = $user->id;
$user->setForcedPassword();
}
UserRole::create([
'user_id' => $userId,
'role_id' => Role::SUPER_ADMIN
]);
}
return to_route('admin.index');
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace Modules\Admin\Http\Controllers;
use Modules\Post\Models\Post;
use Modules\Post\Models\PostCategory;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class AdminPostsController extends Controller
{
public function index()
{
$posts = Post::orderBy('id', 'desc')->get();
return view('admin::posts.index', [
'posts' => $posts
]);
}
public function create()
{
return view('admin::posts.create', [
'categories' => PostCategory::cases()
]);
}
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required',
'category' => 'required',
'short_text' => 'max:500',
'text' => 'required',
'imageFile' => 'required|mimes:jpg,bmp,png'
]);
$path = $request->file('imageFile')->store('posts', ['disk' => 'public']);
$request['image'] = $path;
$post = Post::create(
$request->only(['name', 'short_text', 'text', 'category', 'image'])
);
return to_route('admin.posts');
}
public function edit(Post $post)
{
return view('admin::posts.edit', [
'categories' => PostCategory::cases(),
'post' => $post
]);
}
public function update(Request $request, Post $post)
{
$validated = $request->validate([
'name' => 'required',
'category' => 'required',
'short_text' => 'max:500',
'text' => 'required',
]);
if ($request->file('imageFile'))
{
$path = $request->file('imageFile')->store('posts', ['disk' => 'public']);
$request['image'] = $path;
}
else
{
$reuqest['image'] = $post->image;
}
$post = $post->update(
$request->only(['name', 'short_text', 'text', 'category', 'image'])
);
return to_route('admin.posts');
}
public function delete(Post $post)
{
$post->delete();
return to_route('admin.posts');
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Modules\Admin\Http\Livewire;
use Livewire\Component;
use App\Models\User\UserRole;
use App\Models\User\Role;
class AdminMenu extends Component
{
public $userId;
public function mount()
{
$this->userId = auth()->user()->id;
}
public function render()
{
return view('admin::menu.index', [
'userRoles' => UserRole::where('user_id', $this->userId)->pluck('role_id')->toArray(),
'roles' => Role::class
]);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Modules\Admin\Http\Livewire;
use Livewire\Component;
use Modules\Post\Models\Post;
class Posts extends Component
{
public $userId;
public function mount()
{
$this->userId = auth()->user()->id;
}
public function open($id)
{
$this->dispatch('showPostCardInModal', id: $id);
}
public function render()
{
$posts = Post::all();
return view('admin::posts.list', [
'posts' => $posts
]);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Modules\Admin\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Admin extends Model
{
use HasFactory;
}

View File

@ -0,0 +1,72 @@
<?php
namespace Modules\Admin\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;
use Livewire\Livewire;
class ModuleServiceProvider extends ServiceProvider
{
protected string $moduleName = 'Admin';
public function register()
{
$this->app->register(RouteServiceProvider::class);
}
public function boot()
{
$this->registerViews();
$this->registerLivewireViews();
$this->registerMigrations();
$this->registerConfig();
$this->registerComponent();
$this->registerLivewire();
}
protected function registerViews()
{
$moduleViewsPath = __DIR__ . '/../Views';
$this->loadViewsFrom(
$moduleViewsPath,
strtolower($this->moduleName)
);
}
protected function registerLivewireViews()
{
$moduleViewsPath = __DIR__ . '/../Views/livewire';
$this->loadViewsFrom(
$moduleViewsPath,
strtolower($this->moduleName)
);
}
protected function registerMigrations()
{
$this->loadMigrationsFrom(
app_path('Modules/' . $this->moduleName . '/Database/Migrations')
);
}
protected function registerConfig()
{
$path = app_path('Modules/' . $this->moduleName . '/Config/config.php');
$this->mergeConfigFrom(
$path,
strtolower($this->moduleName)
);
}
protected function registerLivewire()
{
Livewire::component('admin.menu', \Modules\Admin\Http\Livewire\AdminMenu::class);
Livewire::component('admin.posts', \Modules\Admin\Http\Livewire\Posts::class);
}
protected function registerComponent()
{
//Blade::component('<name>', \Modules\<NAME>\Http\Components\<NAME>::class);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Modules\Admin\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
public function map()
{
$this->registerWebRoutes();
}
protected function registerWebRoutes()
{
//Add Web Routes with web Guard
Route::middleware('web')
//Set Default Controllers Namespace
->namespace('Modules\\Admin\\Http\\Controllers')
->group(app_path('Modules/Admin/Routes/web.php'));
}
}

View File

@ -0,0 +1,26 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\Admin\Http\Controllers\AdminController;
Route::middleware(['auth'])->group(function ()
{
Route::get('/admin', [AdminController::class, 'index']);
Route::middleware(['hasAccess'])->group(function ()
{
/** Routes that need to be protected - Маршруты которые нужно защитить */
});
Route::post('/admin/set', [Modules\Admin\Http\Controllers\AdminController::class, 'setSuperAdmin'])->name('admin.setSuperAdmin');
Route::get('/admin', [Modules\Admin\Http\Controllers\AdminController::class, 'index'])->name('admin.index');
Route::get('/admin/posts', [Modules\Admin\Http\Controllers\AdminPostsController::class, 'index'])->name('admin.posts');
Route::get('/admin/posts/create', [Modules\Admin\Http\Controllers\AdminPostsController::class, 'create'])->name('admin.posts.create');
Route::post('/admin/posts/store', [Modules\Admin\Http\Controllers\AdminPostsController::class, 'store'])->name('admin.posts.store');
Route::get('/admin/post/{post}/edit', [Modules\Admin\Http\Controllers\AdminPostsController::class, 'edit'])->name('admin.posts.edit');
Route::post('/admin/post/{post}/update', [Modules\Admin\Http\Controllers\AdminPostsController::class, 'update'])->name('admin.posts.update');
Route::post('/admin/post/{post}/delete', [Modules\Admin\Http\Controllers\AdminPostsController::class, 'delete'])->name('admin.posts.delete');
});

View File

@ -0,0 +1,4 @@
@extends('layouts.admin')
@section('content')
<h1>Дашборд</h1>
@endsection

View File

@ -0,0 +1,44 @@
<div>
@if (in_array($roles::SUPER_ADMIN, $userRoles))
<ul class="nav flex flex-md-column ">
<li>
<h6 class="dropdown-header text-uppercase">Основное</h6>
</li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
href="{{ route('admin.posts') }}">Новости</a>
</li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
href="#">Объекты</a></li>
<li>
<h6 class="dropdown-header text-uppercase">Пользователи</h6>
</li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
href="#">Роли</a></li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
href="#">Список</a>
</li>
<li>
<h6 class="dropdown-header text-uppercase">Справочники</h6>
</li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
href="#">Города</a></li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active" href="#">ЖК</a>
</li>
<li>
<h6 class="dropdown-header text-uppercase">Агентства</h6>
</li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
href="#">Организации</a></li>
<li class="nav-item text-center m-2"><a
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
href="#">Вознаграждения</a></li>
</ul>
@endif
</div>

View File

@ -0,0 +1,53 @@
@extends('layouts.admin')
@section('content')
<link rel="stylesheet" type="text/css" href="https://unpkg.com/trix@2.0.8/dist/trix.css">
<script type="text/javascript" src="https://unpkg.com/trix@2.0.8/dist/trix.umd.min.js"></script>
<h4 class="fw-bold">Добавить новость</h4>
<form action="{{ route('admin.posts.store') }}" method="post" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="titleFormControlTextarea" class="form-label">Заголовок</label>
<textarea class="form-control" id="titleFormControlTextarea1" name="name" rows="2"></textarea>
@error('name')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="row">
<div class="col-6 mb-3">
<label for="categoryFormControlSelect" class="form-label">Категория</label>
<select class="form-select" id="categoryFormControlSelect" name="category" aria-label="">
@foreach ($categories as $category)
<option value="{{ $category->value }}">{{ __($category->name) }}</option>
@endforeach
</select>
@error('category')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="col-6 mb-3">
<label for="formFile" class="form-label">Заставка новости</label>
<input class="form-control" type="file" id="formFile" name="imageFile">
@error('imageFile')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
</div>
<div class="mb-3">
<label for="shortTextFormControlTextarea" class="form-label">Анонс</label>
<textarea class="form-control" id="shortTextFormControlTextarea1" name="short_text" rows="3"></textarea>
@error('short_text')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="shortTextFormControlTextarea" class="form-label">Основной текст</label>
<textarea class="form-control d-none" id="textFormControlTextarea" name="text" rows="15"></textarea>
<trix-editor input="textFormControlTextarea" class="overflow-auto" style="height:300px"></trix-editor>
@error('text')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<button type="submit" class="btn btn-primary">Сохранить</button>
</form>
@endsection

View File

@ -0,0 +1,54 @@
@extends('layouts.admin')
@section('content')
<link rel="stylesheet" type="text/css" href="https://unpkg.com/trix@2.0.8/dist/trix.css">
<script type="text/javascript" src="https://unpkg.com/trix@2.0.8/dist/trix.umd.min.js"></script>
<h4 class="fw-bold">Добавить новость</h4>
<form action="{{ route('admin.posts.update', ['post' => $post]) }}" method="post" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="titleFormControlTextarea" class="form-label">Заголовок</label>
<textarea class="form-control" id="titleFormControlTextarea1" name="name" rows="2">{{ $post->name }}</textarea>
@error('name')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="row">
<div class="col mb-3">
<label for="categoryFormControlSelect" class="form-label">Категория</label>
<select class="form-select" id="categoryFormControlSelect" name="category" aria-label="">
@foreach ($categories as $category)
<option value="{{ $category->value }}" {{ $post->category == $category->value ? 'selected' : '' }}>
{{ __($category->name) }}</option>
@endforeach
</select>
@error('category')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="col mb-3">
<label for="formFile" class="form-label">Заставка новости</label>
<input class="form-control" type="file" id="formFile" name="imageFile">
@error('imageFile')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
</div>
<div class="mb-3">
<label for="shortTextFormControlTextarea" class="form-label">Анонс</label>
<textarea class="form-control" id="shortTextFormControlTextarea1" name="short_text" rows="3">{{ $post->short_text }}</textarea>
@error('short_text')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="shortTextFormControlTextarea" class="form-label">Основной текст</label>
<textarea class="form-control d-none" id="textFormControlTextarea" name="text" rows="15">{{ $post->text }}</textarea>
<trix-editor input="textFormControlTextarea" class="overflow-auto" style="height:300px"></trix-editor>
@error('text')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<button type="submit" class="btn btn-primary">Сохранить</button>
</form>
@endsection

View File

@ -0,0 +1,14 @@
@extends('layouts.admin')
@section('content')
<form class="d-flex mb-3" method="GET" action="{{ route('company.agents.table') }}">
<div class="ms-auto p-2">
<a type="button" class="btn btn-primary py-2 px-3 fs-5" href="{{ route('admin.posts.create') }}">
<i class="bi bi-postcard"></i>
</a>
</div>
</form>
@livewire('admin.posts')
@endsection

View File

@ -0,0 +1,53 @@
<div>
@if ($posts->count() == 0)
<div class="text-center py-5">Нет данных для отображения</div>
@else
<div class="fs-5 bg-light p-0 m-0 border border-1 rounded-4">
<table class="table m-0">
<thead>
<tr scope="col">
<th>ID
<th>Название
<th>Дата создания
<th>
</tr>
</thead>
<tbody class=" ">
@foreach ($posts as $post)
<tr scope="row">
<td class="fw-semibold fs-5 align-middle">
{{ $post->id }}
</td>
<td class="align-middle">
{{ $post->name }}
</td>
<td>
{{ $post->created_at->diffForHumans() }}
</td>
<td>
<div class="dropdown" style="">
<button class="btn btn-light" type="button" id="dropdownMenuButton"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" wire:click="open({{ $post->id }})"
target="_blank">Открыть</a>
<a class="dropdown-item"
href="{{ route('admin.posts.edit', ['post' => $post]) }}">Редактировать</a>
<form method="post"
action="{{ route('admin.posts.delete', ['post' => $post]) }}">
@csrf
<button class="dropdown-item" type="submit">Удалить</button>
</form>
</div>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
@livewire('post.card')
</div>

View File

@ -0,0 +1,29 @@
@extends('layouts.admin')
@section('content')
<h1>Установить глобального администратора</h1>
<form action="{{ route('admin.setSuperAdmin') }}" method="post">
@csrf
<div class="mb-3">
<label for="titleFormControlTextarea" class="form-label">ФИО</label>
<input type="text" class="form-control" id="titleFormControlTextarea1" name="name" rows="2">
@error('name')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="titleFormControlTextarea" class="form-label">Email</label>
<input type="text" class="form-control" id="titleFormControlTextarea1" name="email" rows="2">
@error('name')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="titleFormControlTextarea" class="form-label">Телефон</label>
<input type="text" class="form-control" id="titleFormControlTextarea1" name="phone" rows="2">
@error('name')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<button type="submit" class="btn btn-primary">Создать администратора</button>
</form>
@endsection

View File

@ -0,0 +1,5 @@
<?php
return [
];

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table)
{
$table->id();
$table->string('name');
$table->text('short_text');
$table->text('text');
$table->string('image');
$table->enum('category', ['News', 'Projects', 'Credits', 'Sale'])->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('news');
}
};

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('post_cities', function (Blueprint $table)
{
$table->id();
$table->foreignId('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->foreignId('city_id')->references('id')->on('cities')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('news');
}
};

View File

@ -0,0 +1,20 @@
<?php
namespace Modules\Post\Http\Controllers;
use Modules\Post\Models\Post;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function open(Post $post)
{
return view('post::list.card', [
'post' => $post
]);
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace Modules\Post\Http\Livewire;
use Livewire\Component;
use Livewire\Attributes\On;
use Modules\Post\Models\Post;
use Illuminate\Support\Facades\Storage;
class PostCard extends Component
{
public $id;
public function mount($id = false)
{
$this->id = $id;
}
#[On('showPostCardInModal')]
public function open($id)
{
$this->id = $id;
}
public function close()
{
$this->id = null;
}
public function render()
{
if ($this->id)
{
$post = Post::find($this->id);
if (Storage::disk('public')->exists($post->image))
{
$post->image = Storage::url($post->image);
}
else
{
$post->image = false;
}
return view('post::list.card', [
'post' => $post
]);
}
else
{
return view('post::list.card', [
]);
}
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Modules\Post\Http\Livewire;
use Livewire\Component;
use Illuminate\Support\Facades\Storage;
use Modules\Post\Models\Post;
class PostsList extends Component
{
public $count;
public $filter;
public function mount()
{
}
public function open($id)
{
$this->dispatch('showPostCardInModal', id: $id);
}
public function render()
{
$posts = Post::all();
return view('post::list.cards', [
'posts' => $posts
]);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Modules\Post\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'name',
'short_text',
'text',
'category',
'image'
];
}

View File

@ -0,0 +1,9 @@
<?php
namespace Modules\Post\Models;
enum PostCategory: string
{
case News = "News";
case Projects = "Projects";
case Credits = "Credits";
case Sale = 'Sale';
}

View File

@ -0,0 +1,73 @@
<?php
namespace Modules\Post\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;
use Livewire\Livewire;
class ModuleServiceProvider extends ServiceProvider
{
protected string $moduleName = 'Post';
public function register()
{
$this->app->register(RouteServiceProvider::class);
}
public function boot()
{
$this->registerViews();
$this->registerLivewireViews();
$this->registerMigrations();
$this->registerConfig();
$this->registerComponent();
$this->registerLivewire();
}
protected function registerViews()
{
$moduleViewsPath = __DIR__ . '/../Views';
$this->loadViewsFrom(
$moduleViewsPath,
strtolower($this->moduleName)
);
}
protected function registerLivewireViews()
{
$moduleViewsPath = __DIR__ . '/../Views/livewire';
$this->loadViewsFrom(
$moduleViewsPath,
strtolower($this->moduleName)
);
}
protected function registerMigrations()
{
$this->loadMigrationsFrom(
app_path('Modules/' . $this->moduleName . '/Database/Migrations')
);
}
protected function registerConfig()
{
$path = app_path('Modules/' . $this->moduleName . '/Config/config.php');
$this->mergeConfigFrom(
$path,
strtolower($this->moduleName)
);
}
protected function registerLivewire()
{
Livewire::component('posts.list', \Modules\Post\Http\Livewire\PostsList::class);
Livewire::component('post.card', \Modules\Post\Http\Livewire\PostCard::class);
}
protected function registerComponent()
{
//Blade::component('<name>', \Modules\<NAME>\Http\Components\<NAME>::class);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Modules\Post\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
public function map()
{
$this->registerWebRoutes();
}
protected function registerWebRoutes()
{
//Add Web Routes with web Guard
Route::middleware('web')
//Set Default Controllers Namespace
->namespace('Modules\\Post\\Http\\Controllers')
->group(app_path('Modules/Post/Routes/web.php'));
}
}

View File

@ -0,0 +1,11 @@
<?php
use Illuminate\Support\Facades\Route;
Route::middleware(['auth'])->group(function ()
{
Route::get('/post/{post}', [Modules\Post\Http\Controllers\PostController::class, 'open'])->name('post.open');
});

View File

@ -0,0 +1,4 @@
@extends('layouts.app')
@section('content')
<h1> Example views </h1>
@endsection

View File

@ -0,0 +1,31 @@
<div>
@isset($post)
<div class="modal fade show d-block bg-dark" style="--bs-bg-opacity: .5;" id="postCardModal" data-bs-backdrop="static"
data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
<div class="modal-content">
<div class="modal-header border-0">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"
wire:click="close"></button>
</div>
<div class="modal-body">
@if ($post->image)
<div class="w-100"
style="
height:250px;
background-image:url('{{ $post->image }}');
background-position: center;
background-repeat: no-repeat;
background-size: cover; ">
</div>
@endif
<h1 class="mt-3">{{ $post->name }}</h1>
<p>
{!! $post->text !!}
</p>
</div>
</div>
</div>
</div>
@endisset
</div>

View File

@ -0,0 +1,28 @@
<div class="d-lg-flex row g-3">
@foreach ($posts as $post)
<div class="col-4 m-0 p-2" style="">
<div class="flex-fill placeholder-glow bg-white card">
<div class="row g-0 h-100">
<div class="col-md-6">
<div class="card-body">
<div class="mb-3">
<span
class="badge bg-body-secondary text-dark border-secondary bg-opacity-75 fs-6 rounded-pill">{{ __($post->category) }}</span>
</div>
<h3 class="card-title fs-4">{{ $post->name }}</h3>
</div>
</div>
<div class="col-md-6 bg-secondary bg-opacity-50 rounded-end"
style="height:200px;background-image:url('{{ url('/storage/' . $post->image) }}')">
<a href="#" class="btn btn-light btn-lg rounded-4 position-absolute bottom-0 end-0 m-3"
wire:click="open({{ $post->id }})">
<i class="bi bi-arrow-right"></i>
</a>
</div>
</div>
</div>
</div>
@endforeach
@livewire('post.card')
</div>

View File

@ -5,22 +5,40 @@
use Illuminate\Support\ServiceProvider;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\File;
class AppServiceProvider extends ServiceProvider
{
{
/**
* Register any application services.
*/
public function register(): void
{
//$this->app->register('\\Modules\\Post\\Providers\\ModuleServiceProvider');
//Поиск модулей
$modulesBasePath = app_path('Modules');
foreach (File::directories($modulesBasePath) as $moduleDirectory)
{
//
//Получить имя модуля из имени каталога
$moduleName = basename($moduleDirectory);
$providerClassName = '\\Modules\\' . $moduleName . '\\Providers\\ModuleServiceProvider';
if (class_exists($providerClassName))
{
//Зарегистрировать поставщика услуг модуля, если он существует
$this->app->register($providerClassName);
}
}
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
{
Paginator::useBootstrapFive();
Paginator::useBootstrapFour();
}
}
}

View File

@ -2,7 +2,10 @@
"name": "laravel/laravel",
"type": "project",
"description": "The skeleton application for the Laravel framework.",
"keywords": ["laravel", "framework"],
"keywords": [
"laravel",
"framework"
],
"license": "MIT",
"require": {
"php": "^8.1",
@ -27,7 +30,8 @@
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
"Database\\Seeders\\": "database/seeders/",
"Modules\\": "app/Modules/"
}
},
"autoload-dev": {
@ -66,4 +70,4 @@
},
"minimum-stability": "stable",
"prefer-stable": true
}
}

691
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -28,32 +28,32 @@
|
*/
'disks' => [
'disks' => [
'local' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'throw' => false,
'root' => storage_path('app'),
'throw' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL') . '/storage/app',
'visibility' => 'public',
'throw' => false,
'throw' => false,
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
'throw' => false,
],
],
@ -69,9 +69,9 @@
|
*/
'links' => [
'links' => [
public_path('storage') => storage_path('app/public'),
public_path('lk') => storage_path('public'),
public_path('lk') => storage_path('public'),
],
];

View File

@ -32,5 +32,9 @@
"SoleProperty name": "ФИО полностью",
"contract status new": "Новый",
"Agent was created": "Создана новая учетная запись агента",
"Your account was attached as agent": "Ваша учетная запись была привязана в качестве агента в"
"Your account was attached as agent": "Ваша учетная запись была привязана в качестве агента в",
"Credits": "Ипотека",
"News": "Новости",
"Projects": "Проекты",
"Sale": "Акции"
}

25
package-lock.json generated
View File

@ -4,7 +4,9 @@
"requires": true,
"packages": {
"": {
"name": "lk.zachem.info",
"dependencies": {
"@editorjs/editorjs": "^2.30.8",
"bootstrap": "^5.3.3"
},
"devDependencies": {
@ -16,6 +18,11 @@
"vite": "^5.0.0"
}
},
"node_modules/@editorjs/editorjs": {
"version": "2.30.8",
"resolved": "https://registry.npmjs.org/@editorjs/editorjs/-/editorjs-2.30.8.tgz",
"integrity": "sha512-ClFuxI1qZTfXPJTacQfsJtOUP6bKoIe6BQNdAvGsDTDVwMnZEzoaSOwvUpdZEE56xppVfQueNK/1MElV9SJKHg=="
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@ -888,9 +895,9 @@
"dev": true
},
"node_modules/axios": {
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.15.6",
@ -1165,9 +1172,9 @@
}
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
@ -1328,9 +1335,9 @@
}
},
"node_modules/vite": {
"version": "5.4.10",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz",
"integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
"version": "5.4.17",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.17.tgz",
"integrity": "sha512-5+VqZryDj4wgCs55o9Lp+p8GE78TLVg0lasCH5xFZ4jacZjtqZa6JUw9/p0WeAojaOfncSM6v77InkFPGnvPvg==",
"dev": true,
"dependencies": {
"esbuild": "^0.21.3",

View File

@ -14,6 +14,7 @@
"vite": "^5.0.0"
},
"dependencies": {
"@editorjs/editorjs": "^2.30.8",
"bootstrap": "^5.3.3"
}
}

1
public/lk Symbolic link
View File

@ -0,0 +1 @@
/home/thekindbull/Рабочий стол/laravel_projects/gitea_alfa/lk.zachem.info/storage/public

View File

@ -1 +1 @@
import './bootstrap';
import './bootstrap'

View File

@ -0,0 +1,5 @@
<?php
return [
];

View File

@ -0,0 +1,17 @@
<?php
namespace TeamplateNamespace;
use TeamplateFullModelClass;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class TeamplateClass extends Controller
{
public function index()
{
return view('TeamplateDirectoryName::index');
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace Modules\TeamplateDirectoryName\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;
use Livewire\Livewire;
class ModuleServiceProvider extends ServiceProvider
{
protected String $moduleName = 'TeamplateDirectoryName';
public function register()
{
$this->app->register(RouteServiceProvider::class);
}
public function boot()
{
$this->registerViews();
$this->registerLivewireViews();
$this->registerMigrations();
$this->registerConfig();
$this->registerComponent();
$this->registerLivewire();
}
protected function registerViews()
{
$moduleViewsPath = __DIR__.'/../Views';
$this->loadViewsFrom(
$moduleViewsPath, strtolower($this->moduleName)
);
}
protected function registerLivewireViews()
{
$moduleViewsPath = __DIR__.'/../Views/livewire';
$this->loadViewsFrom(
$moduleViewsPath, strtolower($this->moduleName)
);
}
protected function registerMigrations()
{
$this->loadMigrationsFrom(
app_path('Modules/'.$this->moduleName.'/Database/Migrations')
);
}
protected function registerConfig()
{
$path = app_path('Modules/'.$this->moduleName.'/Config/config.php');
$this->mergeConfigFrom(
$path, strtolower($this->moduleName)
);
}
protected function registerLivewire()
{
//Livewire::component('<name>', \Modules\<NAME>\Http\Livewire\<NAME>::class);
}
protected function registerComponent()
{
//Blade::component('<name>', \Modules\<NAME>\Http\Components\<NAME>::class);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Modules\TeamplateDirectoryName\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
public function map()
{
$this->registerWebRoutes();
}
protected function registerWebRoutes()
{
//Add Web Routes with web Guard
Route::middleware('web')
//Set Default Controllers Namespace
->namespace('Modules\\TeamplateDirectoryName\\Http\\Controllers')
->group(app_path('Modules/TeamplateDirectoryName/Routes/web.php'));
}
}

View File

@ -0,0 +1,13 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\TeamplateDirectoryName\Http\Controllers\TeamplateClass;
Route::middleware(['auth'])->group(function() {
Route::get('/TeamplateRoutePrefix', [TeamplateClass::class, 'index']);
Route::middleware(['hasAccess'])->group(function() {
/** Routes that need to be protected - Маршруты которые нужно защитить */
});
});

View File

@ -0,0 +1,4 @@
@extends('layouts.app')
@section('content')
<h1> Example views </h1>
@endsection

View File

@ -0,0 +1,103 @@
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
@vite(['resources/sass/app.scss', 'resources/js/app.js', 'resources/css/app.css'])
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md bg-body-tertiary shadow-sm">
<div class="container">
<a class="navbar-brand">
<img src={{ url('/images/logo.png') }} alt="Bootstrap" width="70">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ms-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button"
data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
<img src="../../images/icons/user.png" class="img-fluid align-middle"
style="height: 40px;">
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/profile">
Профиль
</a>
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
Выйти
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
<div class="container">
<div class="row justify-content-center">
<div class="col col-sm-2" id="leftPanel">
@livewire('admin.menu')
</div>
<div class="col-10 px-0 px-md-4">
@foreach ($errors->all() as $error)
{{ $error }}
@endforeach
@yield('content')
</div>
</div>
</div>
</main>
</div>
</body>
</html>

View File

@ -1,45 +1 @@
<livewire:mainMenu />
<!--
<ul class="nav flex flex-md-column ">
<li class="nav-item text-center m-2">
<a href="{{ route('home') }}" class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
aria-current="page">
<i class="bi bi-columns-gap"></i> <span class="d-none d-lg-inline text-truncate">Главная</span>
</a>
</li>
<li class="nav-item text-center m-2">
<a href="{{ route('clients.table') }}"
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active" aria-current="page">
<i class="bi bi-person"></i> <span class="d-none d-lg-inline">Клиенты</span>
</a>
</li>
<li class="nav-item text-center m-2">
<a href="/projects" class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
aria-current="page">
<i class="bi bi-book"></i> <span class="d-none d-lg-inline">Проекты</span>
</a>
</li>
<li class="nav-item text-center m-2">
<a href="/news" class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active"
aria-current="page">
<i class="bi bi-layers"></i> <span class="d-none d-lg-inline">Новости</span>
</a>
</li>
<li class="nav-item text-center m-2">
<a href="{{ route('company.agents.table') }}"
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active" aria-current="page">
<i class="bi bi-people"></i> <span class="d-none d-lg-inline">Агенты</span>
</a>
</li>
<li class="nav-item text-center m-2">
<a href="{{ route('company.details') }}"
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active" aria-current="page">
<i class="bi bi-gear"></i> <span class="d-none d-lg-inline">Настройки</span>
</a>
</li>
</ul>
-->
@livewire('mainMenu')

View File

@ -51,6 +51,15 @@ class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active" ar
</li>
@endif
@if (in_array($roles::SUPER_ADMIN, $userRoles))
<li class="nav-item text-center m-2">
<a href="{{ route('admin.index') }}"
class="nav-link d-flex align-items-center gap-2 fs-5 border rounded-4 active" aria-current="page">
<i class="bi bi-gear11"></i> <span class="d-none d-lg-inline">Админка</span>
</a>
</li>
@endif
</ul>

View File

@ -45,65 +45,7 @@ class="list-group-item list-group-item-action p-3 bg-white rounded border border
<div class="fs-5 fw-bold">Новости</div>
<div class="ms-auto p-2">Смотреть все</div>
</div>
<div class="d-lg-flex">
<div class="flex-fill card mb-3 placeholder-glow m-2 bg-white" style="min-height:200px; max-width: 540px;">
<div class="row g-0 h-100">
<div class="col-md-6">
<div class="card-body">
<div class="mb-3">
<span
class="badge bg-body-secondary text-dark border-secondary bg-opacity-75 fs-6 rounded-pill">Акция</span>
</div>
<h3 class="card-title fs-4">Скидка 30% на апартаменты</h3>
</div>
</div>
<div class="col-md-6 bg-secondary bg-opacity-50 rounded-end"
style="height:200px;background-image:url('https://img3.sibdom.ru/images/photo_crop_282_212/houses/photo_main/97/97be/97be2371dd0bba9c4605c3ea6f06e213.jpg')">
<a href="#" class="btn btn-light btn-lg rounded-4 position-absolute bottom-0 end-0 m-3">
<i class="bi bi-arrow-right"></i>
</a>
</div>
</div>
</div>
<div class="flex-fill card mb-3 placeholder-glow m-2 bg-white" style="min-height:200px; max-width: 540px;">
<div class="row g-0 h-100">
<div class="col-md-6">
<div class="card-body">
<div class="mb-3">
<span
class="badge bg-body-secondary text-dark border-secondary bg-opacity-75 fs-6 rounded-pill">Акция</span>
</div>
<h3 class="card-title fs-4">Скидка 30% на апартаменты</h3>
</div>
</div>
<div class="col-md-6 bg-secondary bg-opacity-50 rounded-end"
style="height:200px;background-image:url('https://img3.sibdom.ru/images/photo_crop_282_212/houses/photo_main/97/97be/97be2371dd0bba9c4605c3ea6f06e213.jpg')">
<a href="#" class="btn btn-light btn-lg rounded-4 position-absolute bottom-0 end-0 m-3">
<i class="bi bi-arrow-right"></i>
</a>
</div>
</div>
</div>
<div class="flex-fill card mb-3 placeholder-glow m-2 bg-white" style="min-height:200px; max-width: 540px;">
<div class="row g-0 h-100">
<div class="col-md-6">
<div class="card-body">
<div class="mb-3">
<span
class="badge bg-body-secondary text-dark border-secondary bg-opacity-75 fs-6 rounded-pill">Акция</span>
</div>
<h3 class="card-title fs-4">Скидка 30% на апартаменты</h3>
</div>
</div>
<div class="col-md-6 bg-secondary bg-opacity-50 rounded-end"
style="height:200px;background-image:url('https://img3.sibdom.ru/images/photo_crop_282_212/houses/photo_main/97/97be/97be2371dd0bba9c4605c3ea6f06e213.jpg')">
<a href="#" class="btn btn-light btn-lg rounded-4 position-absolute bottom-0 end-0 m-3">
<i class="bi bi-arrow-right"></i>
</a>
</div>
</div>
</div>
</div>
@livewire(name: 'posts.list')
</div>
<div class="mt-3 col-12">
<div class="d-flex">