Версия 0.1.0 #1
@ -22,6 +22,8 @@ APP_MAINTENANCE_STORE=database
|
||||
#LOGIN_MAX_REQUEST=50
|
||||
#LOGIN_MAX_EMAIL_REQUEST=10
|
||||
|
||||
TINYMCE_LICENSE_KEY="gpl"
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
|
@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Service\Admin\Project\About;
|
||||
|
||||
use App\Dto\Service\Dto;
|
||||
|
||||
final readonly class StoreUpdate extends Dto
|
||||
{
|
||||
public function __construct(
|
||||
private string $title,
|
||||
private string $description,
|
||||
) { }
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ enum Permission: string
|
||||
case Role = 'role';
|
||||
case User = 'user';
|
||||
case Project = 'project';
|
||||
case ProjectContent = 'project-content';
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
@ -15,6 +16,11 @@ public function getPermissions(): array
|
||||
self::AdminPanel => [
|
||||
'view' => __('permissions.Administrative panel allowed'),
|
||||
],
|
||||
self::ProjectContent => [
|
||||
'view' => __('permissions.Allowed to watch'),
|
||||
'create' => __('permissions.Allowed to create'),
|
||||
'update' => __('permissions.Allowed to edit'),
|
||||
],
|
||||
default => $this->getBasePermissions()
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\About\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\AboutService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class AboutController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AboutService $aboutService,
|
||||
) { }
|
||||
|
||||
public function languages(int $project, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->aboutService->languages($project, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/about/languages', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $project, int $language, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->aboutService->edit($project, $language, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/about/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function update(int $project, int $language, StoreUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$data = $request->getDto();
|
||||
$user = $request->user();
|
||||
$result = $this->aboutService->storeOrUpdate($project, $language, $data, $user);
|
||||
if ($result->isError()) {
|
||||
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
|
||||
}
|
||||
|
||||
return redirect()->route('admin.projects.about.edit', [
|
||||
'project' => $project,
|
||||
'language' => $language,
|
||||
])->withSuccess($result->getMessage());
|
||||
}
|
||||
}
|
@ -34,6 +34,17 @@ public function index(IndexRequest $request): View
|
||||
return view('admin/projects/index', $result->getData());
|
||||
}
|
||||
|
||||
public function show(int $id, Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->projectService->show($id, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/show', $result->getData());
|
||||
}
|
||||
|
||||
public function create(Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
|
@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\About;
|
||||
|
||||
use App\Contracts\FormRequestDto;
|
||||
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'title' => ['required', 'string', 'max:255',],
|
||||
'description' => ['nullable', 'string',],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDto(): StoreUpdate
|
||||
{
|
||||
return new StoreUpdate(
|
||||
title: $this->input('title'),
|
||||
description: $this->input('description'),
|
||||
);
|
||||
}
|
||||
}
|
@ -47,4 +47,9 @@ public function languages(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProjectLanguage::class);
|
||||
}
|
||||
|
||||
public function contents(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProjectContent::class);
|
||||
}
|
||||
}
|
||||
|
19
app/application/app/Models/ProjectContent.php
Normal file
19
app/application/app/Models/ProjectContent.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class ProjectContent extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'project_content';
|
||||
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'description',
|
||||
];
|
||||
}
|
29
app/application/app/Policies/ProjectContentPolicy.php
Normal file
29
app/application/app/Policies/ProjectContentPolicy.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\ProjectContent;
|
||||
use App\Models\User;
|
||||
|
||||
final readonly class ProjectContentPolicy extends Policy
|
||||
{
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('project-content.view');
|
||||
}
|
||||
|
||||
public function view(User $user, ProjectContent $projectContent): bool
|
||||
{
|
||||
return $user->hasPermission('project-content.view');
|
||||
}
|
||||
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->hasPermission('project-content.create');
|
||||
}
|
||||
|
||||
public function update(User $user, ProjectContent $projectContent): bool
|
||||
{
|
||||
return $user->hasPermission('project-content.update');
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\ProjectContent;
|
||||
|
||||
final class ProjectContentRepository
|
||||
{
|
||||
public function getContentByLanguageId(int $projectId, int $languageId): ?ProjectContent
|
||||
{
|
||||
return ProjectContent::query()
|
||||
->where(['project_id' => $projectId, 'language_id' => $languageId])
|
||||
->first();
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\ProjectLanguage;
|
||||
|
||||
final class ProjectLanguageRepository
|
||||
{
|
||||
public function isExistsLanguageById(int $projectId, int $languageId): bool
|
||||
{
|
||||
return ProjectLanguage::query()
|
||||
->where(['id' => $languageId, 'project_id' => $projectId])
|
||||
->exists();
|
||||
}
|
||||
}
|
132
app/application/app/Services/Admin/Project/AboutService.php
Normal file
132
app/application/app/Services/Admin/Project/AboutService.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Admin\Project;
|
||||
|
||||
use App\Contracts\ServiceResultError;
|
||||
use App\Dto\Service\Admin\Project\About\StoreUpdate;
|
||||
use App\Models\ProjectContent;
|
||||
use App\Models\User;
|
||||
use App\Repositories\ProjectContentRepository;
|
||||
use App\Repositories\ProjectLanguageRepository;
|
||||
use App\Repositories\ProjectRepository;
|
||||
use App\ServiceResults\ServiceResultArray;
|
||||
use App\ServiceResults\StoreUpdateResult;
|
||||
use App\Services\ProjectContent\ProjectContentCommandHandler;
|
||||
use App\Services\Service;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class AboutService extends Service
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ProjectRepository $projectRepository,
|
||||
private readonly ProjectLanguageRepository $projectLanguageRepository,
|
||||
private readonly ProjectContentRepository $projectContentRepository,
|
||||
private readonly ProjectContentCommandHandler $projectContentCommandHandler,
|
||||
) { }
|
||||
|
||||
public function languages(int $projectId, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($projectId);
|
||||
|
||||
if (is_null($project)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('viewAny', ProjectContent::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'project' => $project,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $languageId, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($projectId);
|
||||
$language = $project?->languages()->firstWhere('id', $languageId);
|
||||
|
||||
if (\is_null($project) || \is_null($language)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
$content = $project->contents()->firstWhere('language_id', $languageId);
|
||||
if (\is_null($content)) {
|
||||
if ($user->cannot('create', ProjectContent::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
$content = new ProjectContent();
|
||||
$content->project_id = $project->id;
|
||||
$content->language_id = $language->id;
|
||||
} else if($user->cannot('update', $content)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'project' => $project,
|
||||
'language' => $language,
|
||||
'content' => $content,
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeOrUpdate(int $projectId, int $languageId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if (! $this->projectLanguageRepository->isExistsLanguageById($projectId, $languageId)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
$content = $this->projectContentRepository->getContentByLanguageId($projectId, $languageId);
|
||||
if (is_null($content)) {
|
||||
return $this->store($projectId, $languageId, $data, $user);
|
||||
}
|
||||
|
||||
return $this->update($content, $data, $user);
|
||||
}
|
||||
|
||||
private function store(int $projectId, int $languageId, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if ($user->cannot('create', ProjectContent::class)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
try {
|
||||
$aboutProject = DB::transaction(function () use ($data, $projectId, $languageId) {
|
||||
$dataAboutProject = $this->getDataAboutProject($data);
|
||||
|
||||
return $this->projectContentCommandHandler->handleStore($projectId, $languageId, $dataAboutProject);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($aboutProject, __('Project information has been successfully updated'));
|
||||
}
|
||||
|
||||
private function update(ProjectContent $content, StoreUpdate $data, User $user): ServiceResultError | StoreUpdateResult
|
||||
{
|
||||
if ($user->cannot('update', $content)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
try {
|
||||
$aboutProject = DB::transaction(function () use ($data, $content) {
|
||||
$dataAboutProject = $this->getDataAboutProject($data);
|
||||
|
||||
return $this->projectContentCommandHandler->handleUpdate($content, $dataAboutProject);
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
return $this->errService(__('Server Error'));
|
||||
}
|
||||
|
||||
return $this->resultStoreUpdateModel($aboutProject, __('Project information has been successfully updated'));
|
||||
}
|
||||
|
||||
private function getDataAboutProject(StoreUpdate $data): array
|
||||
{
|
||||
return [
|
||||
'title' => $data->getTitle(),
|
||||
'description' => $data->getDescription(),
|
||||
];
|
||||
}
|
||||
}
|
@ -50,6 +50,23 @@ public function index(ProjectBuilderDto $projectBuilderDto, QuerySettingsDto $qu
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(int $id, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($id);
|
||||
|
||||
if (is_null($project)) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
|
||||
if ($user->cannot('view', $project)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'project' => $project,
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
if ($user->cannot('create', Project::class)) {
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\ProjectContent;
|
||||
|
||||
use App\Models\ProjectContent;
|
||||
|
||||
final readonly class ProjectContentCommandHandler
|
||||
{
|
||||
public function handleStore(int $projectId, int $languageId, array $data): ProjectContent
|
||||
{
|
||||
$content = new ProjectContent();
|
||||
$content->project_id = $projectId;
|
||||
$content->language_id = $languageId;
|
||||
|
||||
$content->fill($data);
|
||||
$content->save();
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function handleUpdate(ProjectContent $content, array $data): ProjectContent
|
||||
{
|
||||
$content->update($data);
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
43
app/application/app/View/Components/Volt/Forms/Textarea.php
Normal file
43
app/application/app/View/Components/Volt/Forms/Textarea.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Volt\Forms;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class Textarea extends Form
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $title,
|
||||
private readonly string $name,
|
||||
private readonly ?string $value = '',
|
||||
) { }
|
||||
|
||||
protected function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
private function getTitle(): string
|
||||
{
|
||||
return Str::ucfirst($this->title);
|
||||
}
|
||||
|
||||
private function getValue(): string
|
||||
{
|
||||
return (string) old($this->getRequestName(), $this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render(): View
|
||||
{
|
||||
return view('components.volt.forms.textarea', [
|
||||
'title' => $this->getTitle(),
|
||||
'name' => $this->getName(),
|
||||
'requestName' => $this->getRequestName(),
|
||||
'value' => $this->getValue(),
|
||||
]);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\View\Components\Volt\Forms;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class TextareaWysiwyg extends Form
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $title,
|
||||
private readonly string $name,
|
||||
private readonly ?string $value = '',
|
||||
) { }
|
||||
|
||||
protected function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
private function getTitle(): string
|
||||
{
|
||||
return Str::ucfirst($this->title);
|
||||
}
|
||||
|
||||
private function getValue(): string
|
||||
{
|
||||
return (string) old($this->getRequestName(), $this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render(): View
|
||||
{
|
||||
$tinymceLicenseKey = config('tinymce.license_key');
|
||||
|
||||
return view('components.volt.forms.textarea-wysiwyg', [
|
||||
'tinymceLicenseKey' => $tinymceLicenseKey,
|
||||
'title' => $this->getTitle(),
|
||||
'name' => $this->getName(),
|
||||
'requestName' => $this->getRequestName(),
|
||||
'value' => $this->getValue(),
|
||||
]);
|
||||
}
|
||||
}
|
4
app/application/config/tinymce.php
Normal file
4
app/application/config/tinymce.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
return [
|
||||
'license_key' => (string) env('TINYMCE_LICENSE_KEY', 'gpl'),
|
||||
];
|
@ -248,5 +248,6 @@
|
||||
"Add language": "Add language",
|
||||
"There was an error adding a language": "There was an error adding a language",
|
||||
"Select images": "Select images",
|
||||
"loading": "loading"
|
||||
"loading": "loading",
|
||||
"Project information has been successfully updated": "Project information has been successfully updated"
|
||||
}
|
||||
|
@ -5,4 +5,9 @@
|
||||
'Users' => 'Users',
|
||||
'AdminPanel' => 'Admin Panel',
|
||||
'Projects' => 'Projects',
|
||||
'Project' => 'Project',
|
||||
'Sections' => 'Sections',
|
||||
'About project' => 'About the project',
|
||||
'Languages' => 'Languages',
|
||||
'Last update' => 'Last update',
|
||||
];
|
||||
|
@ -10,4 +10,5 @@
|
||||
'Administrative panel allowed' => 'Administrative panel allowed',
|
||||
'AdminPanel' => 'Administrative panel allowed',
|
||||
'Project' => 'Projects',
|
||||
'ProjectContent' => 'About the project',
|
||||
];
|
||||
|
@ -248,5 +248,6 @@
|
||||
"Add language": "Добавить язык",
|
||||
"There was an error adding a language": "Произошла ошибка при добавлении языка",
|
||||
"Select images": "Выберите изображения",
|
||||
"loading": "загрузка"
|
||||
"loading": "загрузка",
|
||||
"Project information has been successfully updated": "Информация о проекте успешно обновлена"
|
||||
}
|
||||
|
@ -5,4 +5,9 @@
|
||||
'Users' => 'Пользователи',
|
||||
'AdminPanel' => 'Админка',
|
||||
'Projects' => 'Проекты',
|
||||
'Project' => 'Проект',
|
||||
'Sections' => 'Разделы',
|
||||
'About project' => 'О проекте',
|
||||
'Languages' => 'Языки',
|
||||
'Last update' => 'Последнее обновление',
|
||||
];
|
||||
|
@ -11,4 +11,5 @@
|
||||
'Administrative panel allowed' => 'Административная панель разрешена',
|
||||
'AdminPanel' => 'Административная панель разрешена',
|
||||
'Project' => 'Проекты',
|
||||
'ProjectContent' => 'О проекте',
|
||||
];
|
||||
|
200
app/application/package-lock.json
generated
200
app/application/package-lock.json
generated
@ -17,6 +17,7 @@
|
||||
"simplebar": "^5.3.4",
|
||||
"smooth-scroll": "^16.1.3",
|
||||
"sweetalert2": "^11.0.18",
|
||||
"tinymce": "^7.0.1",
|
||||
"vanillajs-datepicker": "^1.2.0",
|
||||
"waypoints": "^4.0.1"
|
||||
},
|
||||
@ -24,7 +25,8 @@
|
||||
"axios": "^1.6.4",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"sass-loader": "^13.3.2",
|
||||
"vite": "^5.0"
|
||||
"vite": "^5.0",
|
||||
"vite-plugin-static-copy": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
@ -464,6 +466,41 @@
|
||||
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
|
||||
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "2.0.5",
|
||||
"run-parallel": "^1.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.stat": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.walk": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.scandir": "2.1.5",
|
||||
"fastq": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
@ -1308,6 +1345,22 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.2",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
@ -1315,6 +1368,15 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
||||
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
@ -1360,6 +1422,20 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
|
||||
"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
@ -1395,8 +1471,7 @@
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
@ -1480,6 +1555,18 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/just-extend": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-5.1.1.tgz",
|
||||
@ -1536,6 +1623,28 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
@ -1673,6 +1782,26 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@ -1694,6 +1823,16 @@
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"iojs": ">=1.0.0",
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.13.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.2.tgz",
|
||||
@ -1728,6 +1867,29 @@
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@ -1967,6 +2129,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinymce": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-7.0.1.tgz",
|
||||
"integrity": "sha512-0a7DJnhniBx2psRuKcVQ9g4hujN6PAR4fPS0NSF1T1luH1RBDZVVEn2pGND6Ly+AW1lUm/cHOHjsasqBelMhbw=="
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -1985,6 +2152,15 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||
@ -2096,6 +2272,24 @@
|
||||
"picomatch": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/vite-plugin-static-copy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.2.tgz",
|
||||
"integrity": "sha512-AfmEF+a/mfjsUsrgjbCkhzUCeIUF4EKQXXt3Ie1cour9MBpy6f6GphbdW2td28oYfOrwCyRzFCksgLkpk58q6Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.3",
|
||||
"fast-glob": "^3.2.11",
|
||||
"fs-extra": "^11.1.0",
|
||||
"picocolors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
|
||||
|
@ -18,6 +18,7 @@
|
||||
"simplebar": "^5.3.4",
|
||||
"smooth-scroll": "^16.1.3",
|
||||
"sweetalert2": "^11.0.18",
|
||||
"tinymce": "^7.0.1",
|
||||
"vanillajs-datepicker": "^1.2.0",
|
||||
"waypoints": "^4.0.1"
|
||||
},
|
||||
@ -25,6 +26,7 @@
|
||||
"axios": "^1.6.4",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"sass-loader": "^13.3.2",
|
||||
"vite": "^5.0"
|
||||
"vite": "^5.0",
|
||||
"vite-plugin-static-copy": "^1.0.2"
|
||||
}
|
||||
}
|
||||
|
1
app/application/resources/tinymce/langs/ru.js
Normal file
1
app/application/resources/tinymce/langs/ru.js
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,7 @@
|
||||
@csrf
|
||||
<x-volt.forms.input :title="__('validation.attributes.title')" name="title" type="text" :value="$content->title" required autofocus />
|
||||
<x-volt.forms.textarea-wysiwyg :title="__('validation.attributes.description')" name="description" :value="$content->description" />
|
||||
|
||||
@canany(['create', 'update'], $content)
|
||||
<button class="btn btn-primary" type="submit">{{ __('Save') }}</button>
|
||||
@endcanany
|
@ -0,0 +1,17 @@
|
||||
@section('meta_title', __('admin-sections.Project') . ': ' . $project->name)
|
||||
@section('h1', __('admin-sections.Project') . ': ' . $project->name)
|
||||
<x-admin.layout>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<div class="card border-0 shadow components-section">
|
||||
<div class="card-body">
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.About project') }} ({{ $language->title }})</h3>
|
||||
<form method="post" action="{{ route('admin.projects.about.update', ['project' => $project->id, 'language' => $language->id]) }}">
|
||||
@method('PUT')
|
||||
@include('admin.projects.about._from')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-admin.layout>
|
@ -0,0 +1,42 @@
|
||||
@section('meta_title', __('admin-sections.Project') . ': ' . $project->name)
|
||||
@section('h1', __('admin-sections.Project') . ': ' . $project->name)
|
||||
@php
|
||||
$contents = $project->contents;
|
||||
@endphp
|
||||
<x-admin.layout>
|
||||
<div class="card border-0 shadow mb-4">
|
||||
<div class="card-body">
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.About project') }}</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-centered table-nowrap mb-0 rounded">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th class="border-0">{{ __('admin-sections.Languages') }}</th>
|
||||
<th class="border-0">{{ __('admin-sections.Last update') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($project->languages as $language)
|
||||
@php
|
||||
$content = $contents->firstWhere('language_id', $language->id);
|
||||
@endphp
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.projects.about.edit', ['project' => $project->id, 'language' => $language->id]) }}" class="fw-bold">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
{{ $language->title }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ $content?->updated_at }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-admin.layout>
|
@ -11,6 +11,7 @@
|
||||
<th class="border-0">{{ __('validation.attributes.name') }}</th>
|
||||
<th class="border-0">{{ __('validation.attributes.code') }}</th>
|
||||
<th class="border-0">{{ __('validation.attributes.http_host') }}</th>
|
||||
<th class="border-0">{{ __('validation.attributes.is_public') }}</th>
|
||||
<th class="border-0 rounded-end" style="width: 150px"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -18,9 +19,9 @@
|
||||
@foreach($projects as $project)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.projects.edit', $project) }}" class="fw-bold">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
<a href="{{ route('admin.projects.show', $project) }}" class="fw-bold">
|
||||
<svg data-slot="icon" width="16" height="16" fill="currentColor" class="align-text-top" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z"></path>
|
||||
</svg>
|
||||
{{ $project->name }}
|
||||
</a>
|
||||
@ -32,12 +33,26 @@
|
||||
{{ $project->http_host }}
|
||||
</td>
|
||||
<td>
|
||||
@if($project->is_public)
|
||||
{{ __('Yes') }}
|
||||
@else
|
||||
{{ __('No') }}
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('admin.projects.edit', $project) }}" class="btn btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Edit') }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
</a>
|
||||
@can('delete', $project)
|
||||
<form method="post" action="{{ route('admin.projects.destroy', $project) }}">
|
||||
<form method="post" class="d-inline-block" action="{{ route('admin.projects.destroy', $project) }}">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-danger click-confirm">
|
||||
{{ __('Delete') }}
|
||||
<button type="submit" class="btn btn-danger click-confirm" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Delete') }}">
|
||||
<svg data-slot="icon" fill="currentColor" width="20" height="20" class="align-text-center" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
@endcan
|
||||
|
@ -0,0 +1,32 @@
|
||||
@section('meta_title', __('admin-sections.Project') . ': ' . $project->name)
|
||||
@section('h1', __('admin-sections.Project') . ': ' . $project->name)
|
||||
<x-admin.layout>
|
||||
@include('admin.projects._top')
|
||||
<div class="card border-0 shadow mb-4">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-centered table-nowrap mb-0 rounded">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th class="border-0">{{ __('admin-sections.Sections') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@can('viewAny', \App\Models\ProjectContent::class)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.projects.about.languages', ['project' => $project->id]) }}" class="fw-bold">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
{{ __('admin-sections.About project') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endcan
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-admin.layout>
|
@ -0,0 +1,24 @@
|
||||
<div class="mb-3">
|
||||
<label for="form-textarea-wysiwyg-{{ $requestName }}">{{ $title }}</label>
|
||||
<textarea class="form-control textarea-tinymce @error($requestName) is-invalid @enderror" name="{{ $name }}" id="form-textarea-wysiwyg-{{ $requestName }}" rows="3">{{ $value }}</textarea>
|
||||
@error($requestName)
|
||||
<span class="invalid-feedback">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
@pushOnce('scripts')
|
||||
<script src="{{ asset('/build/tinymce/tinymce.min.js') }}" referrerpolicy="origin"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
tinymce.init({
|
||||
selector: '.textarea-tinymce',
|
||||
@if(in_array(app()->getLocale(), ['ru'], true))
|
||||
language: '{{ app()->getLocale() }}',
|
||||
@endif
|
||||
license_key: '{{ $tinymceLicenseKey }}',
|
||||
plugins: 'advlist code emoticons link lists table codesample',
|
||||
toolbar: 'bold italic | bullist numlist | link emoticons codesample',
|
||||
referrer_policy: 'origin',
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpushonce
|
@ -0,0 +1,7 @@
|
||||
<div class="mb-3">
|
||||
<label for="form-textarea-{{ $requestName }}">{{ $title }}</label>
|
||||
<textarea class="form-control @error($requestName) is-invalid @enderror" name="{{ $name }}" id="form-textarea-{{ $requestName }}" rows="3">{{ $value }}</textarea>
|
||||
@error($requestName)
|
||||
<span class="invalid-feedback">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
@ -18,7 +18,14 @@
|
||||
|
||||
Route::resource('roles', \App\Http\Controllers\Admin\RolesController::class)->only(['index', 'create', 'store', 'edit', 'update', 'destroy'])->where(['role' => '[0-9]+']);
|
||||
|
||||
Route::resource('projects', \App\Http\Controllers\Admin\ProjectsController::class)->only(['index', 'create', 'store', 'edit', 'update', 'destroy'])->where(['project' => '[0-9]+']);
|
||||
Route::resource('projects', \App\Http\Controllers\Admin\ProjectsController::class)->where(['project' => '[0-9]+']);
|
||||
Route::prefix('projects/{project}')->as('projects.')->group(function () {
|
||||
|
||||
Route::get('about', [\App\Http\Controllers\Admin\Projects\AboutController::class, 'languages'])->name('about.languages');
|
||||
Route::get('about/{language}', [\App\Http\Controllers\Admin\Projects\AboutController::class, 'edit'])->name('about.edit')->where(['language' => '[0-9]+']);
|
||||
Route::put('about/{language}', [\App\Http\Controllers\Admin\Projects\AboutController::class, 'update'])->name('about.update')->where(['language' => '[0-9]+']);
|
||||
|
||||
})->where(['project' => '[0-9]+']);
|
||||
|
||||
Route::post('languages/new-language', [\App\Http\Controllers\Admin\LanguagesController::class, 'newLanguage'])->name('new-language');
|
||||
});
|
||||
|
@ -1,14 +1,23 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import laravel from 'laravel-vite-plugin';
|
||||
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
laravel({
|
||||
input: [
|
||||
'resources/volt/scss/app.scss',
|
||||
'resources/volt/js/app.js'
|
||||
'resources/volt/js/app.js',
|
||||
],
|
||||
refresh: true,
|
||||
}),
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
{
|
||||
src: ['node_modules/tinymce/*', 'resources/tinymce/*'],
|
||||
dest: 'tinymce'
|
||||
}
|
||||
]
|
||||
})
|
||||
],
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user