This commit is contained in:
f4ilji
2024-11-05 15:08:08 +05:00
parent e3af1778f0
commit 4b693240e0
41 changed files with 2106 additions and 413 deletions
+7 -1
View File
@@ -6,7 +6,6 @@
<sourceFolder url="file://$MODULE_DIR$/database/factories" isTestSource="false" packagePrefix="Database\Factories\" />
<sourceFolder url="file://$MODULE_DIR$/database/seeders" isTestSource="false" packagePrefix="Database\Seeders\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="Tests\" />
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/vendor/brick/math" />
<excludeFolder url="file://$MODULE_DIR$/vendor/carbonphp/carbon-doctrine-types" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
@@ -173,6 +172,13 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/bezhansalleh/filament-shield" />
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-permission" />
<excludeFolder url="file://$MODULE_DIR$/vendor/vkcom/vk-php-sdk" />
<excludeFolder url="file://$MODULE_DIR$/vendor/nicmart/tree" />
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/browsershot" />
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/crawler" />
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/laravel-sitemap" />
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/robots-txt" />
<excludeFolder url="file://$MODULE_DIR$/vendor/spatie/temporary-directory" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/dom-crawler" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
Generated
+7
View File
@@ -183,6 +183,13 @@
<path value="$PROJECT_DIR$/vendor/bezhansalleh/filament-shield" />
<path value="$PROJECT_DIR$/vendor/spatie/laravel-permission" />
<path value="$PROJECT_DIR$/vendor/vkcom/vk-php-sdk" />
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
<path value="$PROJECT_DIR$/vendor/nicmart/tree" />
<path value="$PROJECT_DIR$/vendor/spatie/temporary-directory" />
<path value="$PROJECT_DIR$/vendor/spatie/robots-txt" />
<path value="$PROJECT_DIR$/vendor/spatie/laravel-sitemap" />
<path value="$PROJECT_DIR$/vendor/spatie/browsershot" />
<path value="$PROJECT_DIR$/vendor/spatie/crawler" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.1" />
+25 -15
View File
@@ -1,32 +1,42 @@
server {
client_max_body_size 200M;
large_client_header_buffers 4 128k;
client_max_body_size 200M; # Максимальный размер тела запроса
large_client_header_buffers 4 128k; # Размеры буферов для заголовков
root /var/www/public;
location / {
add_header Access-Control-Allow-Origin *;
try_files $uri /index.php?$args;
add_header Access-Control-Allow-Origin *; # Заголовок для CORS
try_files $uri /index.php?$args; # Обработка запросов
}
location /sveden/ {
alias /var/www/public/sveden/;
index index.html;
try_files $uri $uri/ /sveden/index.html;
try_files $uri $uri/ /sveden/index.html; # Обработка статических файлов
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
try_files $uri =404; # Если файл не найден, возвращаем 404
fastcgi_split_path_info ^(.+\.php)(/.+)$; # Разделение пути
fastcgi_pass app:9000; # Указываем сервер PHP-FPM
fastcgi_index index.php; # Индексный файл
include fastcgi_params; # Включаем параметры FastCGI
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # Путь к скрипту
fastcgi_param PATH_INFO $fastcgi_path_info; # Информация о пути
fastcgi_buffers 16 16k; # Увеличение буферов FastCGI
fastcgi_buffer_size 32k; # Размер буфера FastCGI
}
# Защита от доступа к конфиденциальным файлам
location ~ /\.ht {
deny all; # Запрет доступа к файлам .htaccess
}
# Настройки кэширования для статических файлов
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf|otf)$ {
expires 30d; # Кэширование на 30 дней
add_header Cache-Control "public, no-transform"; # Заголовок кэширования
}
}
+97
View File
@@ -0,0 +1,97 @@
<?php
namespace App\Console\Commands;
use App\Enums\PostStatus;
use App\Models\Event;
use App\Models\Page;
use App\Models\Post;
use Illuminate\Console\Command;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
class GenerateSitemap extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'sitemap:generate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Генерирует карту сайта';
/**
* Execute the console command.
*/
public function handle()
{
$sitemap = Sitemap::create();
$this->generatePages($sitemap);
$this->generatePosts($sitemap);
$this->generateEvents($sitemap);
$sitemap->writeToFile(public_path('sitemap.xml'));
}
protected function generatePages(Sitemap $sitemap)
{
$pages = Page::query()
->where('is_visible', true)
->where('code', 200)
->get();
$this->addUrlsToSitemap($sitemap, $pages, function($page) {
return [
'path' => "/{$page->path}",
'lastModificationDate' => $page->updated_at,
'priority' => 0.5,
];
});
}
protected function generateEvents(Sitemap $sitemap)
{
$events = Event::query()
->get();
$this->addUrlsToSitemap($sitemap, $events, function($event) {
return [
'path' => "/events/{$event->slug}",
'lastModificationDate' => $event->updated_at,
'priority' => 0.5,
];
});
}
protected function generatePosts(Sitemap $sitemap)
{
$posts = Post::query()
->where('status', PostStatus::PUBLISHED)
->get();
$this->addUrlsToSitemap($sitemap, $posts, function($post) {
return [
'path' => "/news/{$post->slug}",
'lastModificationDate' => $post->updated_at,
'priority' => 0.5,
];
});
}
protected function addUrlsToSitemap(Sitemap $sitemap, $items, callable $callback)
{
foreach ($items as $item) {
$urlData = $callback($item);
$sitemap->add(Url::create($urlData['path'])
->setLastModificationDate($urlData['lastModificationDate'])
->setPriority($urlData['priority']));
}
}
}
@@ -29,20 +29,15 @@ class CreateAcademicJournal extends CreateRecord
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['about_program']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['about_program']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['main_info']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
} $image = ($data['preview'] !== null) ? $data['preview'] : null;
}
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -68,22 +63,6 @@ class CreateAcademicJournal extends CreateRecord
return $data;
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function getDataFromBlocks($block) : string
{
@@ -28,41 +28,19 @@ class EditAcademicJournal extends EditRecord
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['about_program']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['about_program']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['main_info']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
$image = ($this->record->preview !== null) ? $this->record->preview : null;
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -11,10 +11,14 @@ class CreateAdditionalEducation extends CreateRecord
{
protected static string $resource = AdditionalEducationResource::class;
protected array $seoData;
protected function mutateFormDataBeforeCreate(array $data): array
{
$this->seoData = $this->generateSeo($data);
$data['search_data'] = $this->generateSearchData($data['content']);
return $data;
}
@@ -27,17 +31,16 @@ class CreateAdditionalEducation extends CreateRecord
{
$title = $data['title'];
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
$description = strip_tags($rowData['data']['content']);
// $image = ($data['preview'] !== null) ? $data['preview'] : null;
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
return [
'title' => $title,
'description' => Str::limit($description, 160),
'image' => "",
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
];
}
private function getFirstBlockByName(string $name, array $content) : array|null
{
$data = null;
@@ -48,21 +51,17 @@ class CreateAdditionalEducation extends CreateRecord
return $data;
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
private function generateSearchData(array $data) : string
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
$result = "";
foreach ($data as $block) {
$result .= $this->getDataFromBlocks($block);
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
// Удаляем лишние пробелы и переносы строк
$result = preg_replace('/\s+/', ' ', $result);
$result = trim($result);
return strtolower($result);
}
private function getDataFromBlocks($block) : string
@@ -14,33 +14,37 @@ class EditAdditionalEducation extends EditRecord
protected array $seoData;
protected function mutateFormDataBeforeSave(array $data): array
{
$this->seoData = $this->generateSeo($data);
$data['search_data'] = $this->generateSearchData($data['content']);
return $data;
}
protected function afterSave(): void
{
$this->record->seo()->update($this->seoData);
}
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
$description = strip_tags($rowData['data']['content']);
// $image = ($data['preview'] !== null) ? $data['preview'] : null;
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
return [
'title' => $title,
'description' => Str::limit($description, 160),
'image' => "",
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
];
}
private function getFirstBlockByName(string $name, array $content) : array|null
{
$data = null;
@@ -51,6 +55,56 @@ class EditAdditionalEducation extends EditRecord
return $data;
}
private function generateSearchData(array $data) : string
{
$result = "";
foreach ($data as $block) {
$result .= $this->getDataFromBlocks($block);
}
// Удаляем лишние пробелы и переносы строк
$result = preg_replace('/\s+/', ' ', $result);
$result = trim($result);
return strtolower($result);
}
private function getDataFromBlocks($block) : string
{
$data = "";
switch ($block['type']) {
case 'paragraph':
$data .= strip_tags($block['data']['content']) . " ";
break;
case 'heading':
$data .= strip_tags($block['data']['content']) . " ";
break;
case 'files':
foreach ($block['data']['file'] as $file) {
$data .= $file['title'] . " ";
}
break;
case 'person':
$data .= $block['data']['name'] . " ";
break;
case 'stepper':
$data .= $block['data']['step_name'] . " ";
foreach ($block['data']['steps'] as $step) {
$data .= $step['title'] . " ";
$data .= strip_tags($step['content']) . " ";
}
break;
case 'tabs':
foreach ($block['data']['tab'] as $item) {
foreach ($item['content'] as $block) {
$data .= $this->getDataFromBlocks($block);
};
};
break;
}
return $data;
}
protected function getHeaderActions(): array
+412 -13
View File
@@ -2,25 +2,43 @@
namespace App\Filament\Resources;
use App\Enums\CustomFormStatus;
use App\Enums\PostStatus;
use App\Filament\Resources\DepartmentResource\Pages;
use App\Filament\Resources\DepartmentResource\RelationManagers;
use App\Helpers\ByteConverter;
use App\Models\Category;
use App\Models\CustomForm;
use App\Models\Department;
use App\Models\Faculty;
use App\Models\Page;
use App\Models\PageReferenceList;
use App\Models\Post;
use Filament\Forms;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
class DepartmentResource extends Resource
{
protected static ?string $model = Department::class;
protected static ?string $navigationGroup = 'Структура института';
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $pluralLabel = 'Кафедры';
@@ -34,21 +52,402 @@ class DepartmentResource extends Resource
{
return $form
->schema([
TextInput::make('title')->label('Название кафедры')->required()
->live(onBlur: true)
->afterStateUpdated(function (string $operation, $state, Forms\Set $set) {
$set('slug', Str::slug($state));
}),
TextInput::make('slug')->label('Slug')->unique(ignoreRecord: true)->readOnly()->required(),
Forms\Components\Select::make('faculty_id')
->options(Faculty::all()->pluck('title', 'id'))
->label('Факультет')
->required(),
Toggle::make('is_active')->default(true)->label('Активная кафедра')->inline(false),
Section::make()
->schema([
Tabs::make('Tabs')
->tabs([
Tabs\Tab::make('Основная информация')
->schema([
TextInput::make('title')->label('Название факультета')->required()
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set) {
$set('slug', Str::slug($state));
$set('seo.title', $state);
}),
TextInput::make('slug')->label('Slug')->unique(ignoreRecord: true)->readOnly()->required(),
Toggle::make('is_active')->default(true)->label('Активный факультет')->inline(false),
Forms\Components\Select::make('faculty_id')
->options(Faculty::all()->pluck('title', 'id'))
->label('Факультет')
->required(),
]),
Tabs\Tab::make('Описание факультета')
->schema([
Builder::make('content')->label('')->blocks([
Builder\Block::make('heading')->label('Заголовок')
->schema([
TextInput::make('id')->hidden()->integer()->default(rand(2335235,324634264263426)),
TextInput::make('content')
->label('')
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string $state, Forms\Set $set, $get) {
}),
]),
Builder\Block::make('paragraph')
->schema([
RichEditor::make('content')
->toolbarButtons([
'blockquote',
'bold',
'bulletList',
'italic',
'link',
'orderedList',
'redo',
'strike',
'underline',
'undo',
])
->label(''),
])->label('Текст'),
Builder\Block::make('files')
->schema([
Forms\Components\Repeater::make('file')->schema([
Hidden::make('expansion')->required(),
Hidden::make('size')->required(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->getUploadedFileNameForStorageUsing(
fn (TemporaryUploadedFile $file): string =>
str(Str::slug(pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME) . '-' . Carbon::now()->timestamp ) . '.' . $file->getClientOriginalExtension())
)
->acceptedFileTypes([
'application/pdf',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/zip'
])
->maxSize(512000)
->disk('public')
->directory('files')
->downloadable()
->afterStateUpdated(function ($set, $state) {
$set('expansion', $state?->getClientOriginalExtension());
$set('size', ByteConverter::bytesToHuman($state?->getSize()));
})
->visibility('public')
]),
]),
Builder\Block::make('person')
->schema([
TextInput::make('name')
->label('Имя')
->required()
->maxLength(255),
FileUpload::make('photo')
->label('Фотография')
->image()
->disk('public')
->directory('images')
->imageEditor(),
Forms\Components\Repeater::make('info')->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('column')
->required()
->maxLength(255),
TextInput::make('content')
->required()
->maxLength(255),
]),
])->minItems(1),
]),
Builder\Block::make('stepper')
->schema([
TextInput::make('step_name')
->label('Название шага')
->required()
->maxLength(255),
Forms\Components\Repeater::make('steps')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
RichEditor::make('content')->required(),
])->minItems(1),
]),
Builder\Block::make('tabs')
->schema([
Forms\Components\Repeater::make('tab')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
\Filament\Forms\Components\Builder::make('content')->label('')->blocks([
Builder\Block::make('heading')->label('Заголовок')
->schema([
TextInput::make('id')->hidden()->integer()->default(rand(2335235,324634264263426)),
TextInput::make('content')
->label('')
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string $state, Forms\Set $set, $get) {
}),
]),
Builder\Block::make('paragraph')
->schema([
RichEditor::make('content')
->toolbarButtons([
'blockquote',
'bold',
'bulletList',
'italic',
'link',
'orderedList',
'redo',
'strike',
'underline',
'undo',
])
->label(''),
])->label('Текст'),
Builder\Block::make('files')
->schema([
Forms\Components\Repeater::make('file')->schema([
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'application/pdf',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/zip'
])
->maxSize(512000)
->disk('public')
->directory('files')
->downloadable()
->visibility('public')
]),
]),
Builder\Block::make('person')
->schema([
TextInput::make('name')
->label('Имя')
->required()
->maxLength(255),
FileUpload::make('photo')
->label('Фотография')
->image()
->disk('public')
->directory('images')
->imageEditor(),
Forms\Components\Repeater::make('info')->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('column')
->required()
->maxLength(255),
TextInput::make('content')
->required()
->maxLength(255),
]),
])->minItems(1),
]),
Builder\Block::make('stepper')
->schema([
TextInput::make('step_name')
->label('Название шага')
->required()
->maxLength(255),
Forms\Components\Repeater::make('steps')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
RichEditor::make('content')->required(),
])->minItems(1),
]),
Builder\Block::make('images')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Слайдер изображений'),
Builder\Block::make('image')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Изображение'),
Builder\Block::make('video')
->schema([
TextInput::make('mime')->readOnly(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'video/mp4',
'video/quicktime',
'video/x-msvideo',
'video/x-ms-wmv',
'video/avi',
'video/webm',
'video/ogg',
'video/3gpp',
'video/3gpp2',
'video/x-m4v',
])
->disk('public')
->directory('videos')
->afterStateUpdated(fn (callable $set, $state) => $set('mime', $state?->getMimeType())),
]),
Builder\Block::make('postsList')
->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('count')
->label('Количество запией')
->integer(),
Select::make('category')
->options(Category::all()->pluck('title', 'id'))
]),
])->label('Список новостей'),
])
->collapsed()
->blockNumbers(false)
->collapsible()
->addActionLabel('Добавить новый блок'),
])->minItems(1),
]),
Builder\Block::make('images')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Слайдер изображений'),
Builder\Block::make('image')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Изображение'),
Builder\Block::make('video')
->schema([
TextInput::make('mime')->readOnly(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'video/mp4',
'video/quicktime',
'video/x-msvideo',
'video/x-ms-wmv',
'video/avi',
'video/webm',
'video/ogg',
'video/3gpp',
'video/3gpp2',
'video/x-m4v',
])
->disk('public')
->directory('videos')
->afterStateUpdated(fn (callable $set, $state) => $set('mime', $state?->getMimeType())),
]),
Builder\Block::make('postsList')
->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('count')
->label('Количество запией')
->integer(),
Select::make('category')
->options(Category::all()->pluck('title', 'id'))
]),
])->label('Список новостей'),
Builder\Block::make('postItem')
->schema([
Select::make('post')
->options(Post::query()->where('status', PostStatus::PUBLISHED)->pluck('title', 'id'))
->searchable()
->required(),
])->label('Новость'),
Builder\Block::make('pageItem')
->schema([
Select::make('page')
->options(Page::query()->where('title', '!=' , null)->where('is_visible', true)->pluck('title', 'id'))
->searchable()
->required(),
])->label('Страница'),
Builder\Block::make('customForm')
->schema([
Select::make('form')
->options(CustomForm::query()->where('status', CustomFormStatus::PUBLISHED)->pluck('title', 'form_id'))
->searchable()
->required(),
])->label('Форма'),
Builder\Block::make('pageResourceList')
->schema([
Select::make('resource')
->options(PageReferenceList::query()->where('is_active', true)->pluck('title', 'slug'))
->searchable()
->required(),
])->label('Ресурсы'),
])
->collapsed()
->blockNumbers(false)
->collapsible()
->required()
->blockPickerColumns(3)
->blockPickerWidth('2xl')
->addActionLabel('Добавить новый блок'),
]),
]),
])
]);
}
public static function table(Table $table): Table
{
return $table
@@ -13,7 +13,6 @@ class CreateDepartment extends CreateRecord
protected array $seoData;
protected function mutateFormDataBeforeCreate(array $data): array
{
$this->seoData = $this->generateSeo($data);
@@ -29,20 +28,15 @@ class CreateDepartment extends CreateRecord
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
} $image = ($data['preview'] !== null) ? $data['preview'] : null;
}
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -68,22 +62,6 @@ class CreateDepartment extends CreateRecord
return $data;
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function getDataFromBlocks($block) : string
{
@@ -28,41 +28,19 @@ class EditDepartment extends EditRecord
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
$image = ($this->record->preview !== null) ? $this->record->preview : null;
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -29,20 +29,15 @@ class CreateDivision extends CreateRecord
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['description']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['description']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['description']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
} $image = ($data['preview'] !== null) ? $data['preview'] : null;
}
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -28,41 +28,19 @@ class EditDivision extends EditRecord
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['description']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['description']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['description']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
$image = ($this->record->preview !== null) ? $this->record->preview : null;
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -33,20 +33,15 @@ class CreateEducationalProgram extends CreateRecord
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['about_program']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
} $image = ($data['preview'] !== null) ? $data['preview'] : null;
}
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -72,23 +67,6 @@ class CreateEducationalProgram extends CreateRecord
return $data;
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function getDataFromBlocks($block) : string
{
$data = "";
@@ -13,10 +13,8 @@ class EditEducationalProgram extends EditRecord
{
protected static string $resource = EducationalProgramResource::class;
protected array $seoData;
protected function mutateFormDataBeforeSave(array $data): array
{
$this->seoData = $this->generateSeo($data);
@@ -30,42 +28,18 @@ class EditEducationalProgram extends EditRecord
$this->record->seo()->update($this->seoData);
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['about_program']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
$image = ($this->record->preview !== null) ? $this->record->preview : null;
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -2,17 +2,33 @@
namespace App\Filament\Resources\FacultyRecourceResource\RelationManagers;
use App\Enums\CustomFormStatus;
use App\Enums\PostStatus;
use App\Helpers\ByteConverter;
use App\Models\Category;
use App\Models\CustomForm;
use App\Models\Faculty;
use App\Models\Page;
use App\Models\PageReferenceList;
use App\Models\Post;
use Filament\Forms;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
class DepartmentsRelationManager extends RelationManager
{
@@ -25,13 +41,391 @@ class DepartmentsRelationManager extends RelationManager
{
return $form
->schema([
TextInput::make('title')->label('Название кафедры')->required()
->live(onBlur: true)
->afterStateUpdated(function (string $operation, $state, Forms\Set $set) {
$set('slug', Str::slug($state));
}),
TextInput::make('slug')->label('Slug')->unique(ignoreRecord: true)->readOnly()->required(),
Toggle::make('is_active')->default(true)->label('Активная кафедра')->inline(false),
Section::make()
->schema([
Tabs::make('Tabs')
->tabs([
Tabs\Tab::make('Основная информация')
->schema([
TextInput::make('title')->label('Название факультета')->required()
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set) {
$set('slug', Str::slug($state));
$set('seo.title', $state);
}),
TextInput::make('slug')->label('Slug')->unique(ignoreRecord: true)->readOnly()->required(),
Toggle::make('is_active')->default(true)->label('Активный факультет')->inline(false),
]),
Tabs\Tab::make('Описание факультета')
->schema([
Builder::make('content')->label('')->blocks([
Builder\Block::make('heading')->label('Заголовок')
->schema([
TextInput::make('id')->hidden()->integer()->default(rand(2335235,324634264263426)),
TextInput::make('content')
->label('')
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string $state, Forms\Set $set, $get) {
}),
]),
Builder\Block::make('paragraph')
->schema([
RichEditor::make('content')
->toolbarButtons([
'blockquote',
'bold',
'bulletList',
'italic',
'link',
'orderedList',
'redo',
'strike',
'underline',
'undo',
])
->label(''),
])->label('Текст'),
Builder\Block::make('files')
->schema([
Forms\Components\Repeater::make('file')->schema([
Hidden::make('expansion')->required(),
Hidden::make('size')->required(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->getUploadedFileNameForStorageUsing(
fn (TemporaryUploadedFile $file): string =>
str(Str::slug(pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME) . '-' . Carbon::now()->timestamp ) . '.' . $file->getClientOriginalExtension())
)
->acceptedFileTypes([
'application/pdf',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/zip'
])
->maxSize(512000)
->disk('public')
->directory('files')
->downloadable()
->afterStateUpdated(function ($set, $state) {
$set('expansion', $state?->getClientOriginalExtension());
$set('size', ByteConverter::bytesToHuman($state?->getSize()));
})
->visibility('public')
]),
]),
Builder\Block::make('person')
->schema([
TextInput::make('name')
->label('Имя')
->required()
->maxLength(255),
FileUpload::make('photo')
->label('Фотография')
->image()
->disk('public')
->directory('images')
->imageEditor(),
Forms\Components\Repeater::make('info')->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('column')
->required()
->maxLength(255),
TextInput::make('content')
->required()
->maxLength(255),
]),
])->minItems(1),
]),
Builder\Block::make('stepper')
->schema([
TextInput::make('step_name')
->label('Название шага')
->required()
->maxLength(255),
Forms\Components\Repeater::make('steps')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
RichEditor::make('content')->required(),
])->minItems(1),
]),
Builder\Block::make('tabs')
->schema([
Forms\Components\Repeater::make('tab')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
\Filament\Forms\Components\Builder::make('content')->label('')->blocks([
Builder\Block::make('heading')->label('Заголовок')
->schema([
TextInput::make('id')->hidden()->integer()->default(rand(2335235,324634264263426)),
TextInput::make('content')
->label('')
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string $state, Forms\Set $set, $get) {
}),
]),
Builder\Block::make('paragraph')
->schema([
RichEditor::make('content')
->toolbarButtons([
'blockquote',
'bold',
'bulletList',
'italic',
'link',
'orderedList',
'redo',
'strike',
'underline',
'undo',
])
->label(''),
])->label('Текст'),
Builder\Block::make('files')
->schema([
Forms\Components\Repeater::make('file')->schema([
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'application/pdf',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/zip'
])
->maxSize(512000)
->disk('public')
->directory('files')
->downloadable()
->visibility('public')
]),
]),
Builder\Block::make('person')
->schema([
TextInput::make('name')
->label('Имя')
->required()
->maxLength(255),
FileUpload::make('photo')
->label('Фотография')
->image()
->disk('public')
->directory('images')
->imageEditor(),
Forms\Components\Repeater::make('info')->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('column')
->required()
->maxLength(255),
TextInput::make('content')
->required()
->maxLength(255),
]),
])->minItems(1),
]),
Builder\Block::make('stepper')
->schema([
TextInput::make('step_name')
->label('Название шага')
->required()
->maxLength(255),
Forms\Components\Repeater::make('steps')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
RichEditor::make('content')->required(),
])->minItems(1),
]),
Builder\Block::make('images')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Слайдер изображений'),
Builder\Block::make('image')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Изображение'),
Builder\Block::make('video')
->schema([
TextInput::make('mime')->readOnly(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'video/mp4',
'video/quicktime',
'video/x-msvideo',
'video/x-ms-wmv',
'video/avi',
'video/webm',
'video/ogg',
'video/3gpp',
'video/3gpp2',
'video/x-m4v',
])
->disk('public')
->directory('videos')
->afterStateUpdated(fn (callable $set, $state) => $set('mime', $state?->getMimeType())),
]),
Builder\Block::make('postsList')
->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('count')
->label('Количество запией')
->integer(),
Select::make('category')
->options(Category::all()->pluck('title', 'id'))
]),
])->label('Список новостей'),
])
->collapsed()
->blockNumbers(false)
->collapsible()
->addActionLabel('Добавить новый блок'),
])->minItems(1),
]),
Builder\Block::make('images')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Слайдер изображений'),
Builder\Block::make('image')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Изображение'),
Builder\Block::make('video')
->schema([
TextInput::make('mime')->readOnly(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'video/mp4',
'video/quicktime',
'video/x-msvideo',
'video/x-ms-wmv',
'video/avi',
'video/webm',
'video/ogg',
'video/3gpp',
'video/3gpp2',
'video/x-m4v',
])
->disk('public')
->directory('videos')
->afterStateUpdated(fn (callable $set, $state) => $set('mime', $state?->getMimeType())),
]),
Builder\Block::make('postsList')
->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('count')
->label('Количество запией')
->integer(),
Select::make('category')
->options(Category::all()->pluck('title', 'id'))
]),
])->label('Список новостей'),
Builder\Block::make('postItem')
->schema([
Select::make('post')
->options(Post::query()->where('status', PostStatus::PUBLISHED)->pluck('title', 'id'))
->searchable()
->required(),
])->label('Новость'),
Builder\Block::make('pageItem')
->schema([
Select::make('page')
->options(Page::query()->where('title', '!=' , null)->where('is_visible', true)->pluck('title', 'id'))
->searchable()
->required(),
])->label('Страница'),
Builder\Block::make('customForm')
->schema([
Select::make('form')
->options(CustomForm::query()->where('status', CustomFormStatus::PUBLISHED)->pluck('title', 'form_id'))
->searchable()
->required(),
])->label('Форма'),
Builder\Block::make('pageResourceList')
->schema([
Select::make('resource')
->options(PageReferenceList::query()->where('is_active', true)->pluck('title', 'slug'))
->searchable()
->required(),
])->label('Ресурсы'),
])
->collapsed()
->blockNumbers(false)
->collapsible()
->required()
->blockPickerColumns(3)
->blockPickerWidth('2xl')
->addActionLabel('Добавить новый блок'),
]),
]),
])
]);
}
+403 -12
View File
@@ -2,21 +2,37 @@
namespace App\Filament\Resources;
use App\Enums\CustomFormStatus;
use App\Enums\PostStatus;
use App\Filament\Resources\FacultyRecourceResource\RelationManagers\DepartmentsRelationManager;
use App\Filament\Resources\FacultyResource\Pages;
use App\Filament\Resources\FacultyResource\RelationManagers;
use App\Filament\Resources\FacultyResource\RelationManagers\WorkersRelationManager;
use App\Helpers\ByteConverter;
use App\Models\Category;
use App\Models\CustomForm;
use App\Models\Faculty;
use App\Models\Page;
use App\Models\PageReferenceList;
use App\Models\Post;
use Filament\Forms;
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
class FacultyResource extends Resource
{
@@ -36,16 +52,392 @@ class FacultyResource extends Resource
{
return $form
->schema([
TextInput::make('title')->label('Название факультета')->required(),
TextInput::make('abbreviation')->label('Аббревиатура')->required()
->live(onBlur: true)
->afterStateUpdated(function (string $operation, $state, Forms\Set $set) {
$set('slug', Str::slug($state));
}),
TextInput::make('slug')->label('Slug')->unique(ignoreRecord: true)->readOnly()->required(),
Toggle::make('is_active')->default(true)->label('Активный факультет')->inline(false),
]);
Section::make()
->schema([
Tabs::make('Tabs')
->tabs([
Tabs\Tab::make('Основная информация')
->schema([
TextInput::make('title')->label('Название факультета')->required()
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string|null $state, Forms\Set $set) {
$set('slug', Str::slug($state));
$set('seo.title', $state);
}),
TextInput::make('slug')->label('Slug')->unique(ignoreRecord: true)->readOnly()->required(),
Toggle::make('is_active')->default(true)->label('Активный факультет')->inline(false),
]),
Tabs\Tab::make('Описание факультета')
->schema([
Builder::make('content')->label('')->blocks([
Builder\Block::make('heading')->label('Заголовок')
->schema([
TextInput::make('id')->hidden()->integer()->default(rand(2335235,324634264263426)),
TextInput::make('content')
->label('')
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string $state, Forms\Set $set, $get) {
}),
]),
Builder\Block::make('paragraph')
->schema([
RichEditor::make('content')
->toolbarButtons([
'blockquote',
'bold',
'bulletList',
'italic',
'link',
'orderedList',
'redo',
'strike',
'underline',
'undo',
])
->label(''),
])->label('Текст'),
Builder\Block::make('files')
->schema([
Forms\Components\Repeater::make('file')->schema([
Hidden::make('expansion')->required(),
Hidden::make('size')->required(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->getUploadedFileNameForStorageUsing(
fn (TemporaryUploadedFile $file): string =>
str(Str::slug(pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME) . '-' . Carbon::now()->timestamp ) . '.' . $file->getClientOriginalExtension())
)
->acceptedFileTypes([
'application/pdf',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/zip'
])
->maxSize(512000)
->disk('public')
->directory('files')
->downloadable()
->afterStateUpdated(function ($set, $state) {
$set('expansion', $state?->getClientOriginalExtension());
$set('size', ByteConverter::bytesToHuman($state?->getSize()));
})
->visibility('public')
]),
]),
Builder\Block::make('person')
->schema([
TextInput::make('name')
->label('Имя')
->required()
->maxLength(255),
FileUpload::make('photo')
->label('Фотография')
->image()
->disk('public')
->directory('images')
->imageEditor(),
Forms\Components\Repeater::make('info')->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('column')
->required()
->maxLength(255),
TextInput::make('content')
->required()
->maxLength(255),
]),
])->minItems(1),
]),
Builder\Block::make('stepper')
->schema([
TextInput::make('step_name')
->label('Название шага')
->required()
->maxLength(255),
Forms\Components\Repeater::make('steps')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
RichEditor::make('content')->required(),
])->minItems(1),
]),
Builder\Block::make('tabs')
->schema([
Forms\Components\Repeater::make('tab')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
\Filament\Forms\Components\Builder::make('content')->label('')->blocks([
Builder\Block::make('heading')->label('Заголовок')
->schema([
TextInput::make('id')->hidden()->integer()->default(rand(2335235,324634264263426)),
TextInput::make('content')
->label('')
->live(onBlur: true)
->afterStateUpdated(function (string $operation, string $state, Forms\Set $set, $get) {
}),
]),
Builder\Block::make('paragraph')
->schema([
RichEditor::make('content')
->toolbarButtons([
'blockquote',
'bold',
'bulletList',
'italic',
'link',
'orderedList',
'redo',
'strike',
'underline',
'undo',
])
->label(''),
])->label('Текст'),
Builder\Block::make('files')
->schema([
Forms\Components\Repeater::make('file')->schema([
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'application/pdf',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/zip'
])
->maxSize(512000)
->disk('public')
->directory('files')
->downloadable()
->visibility('public')
]),
]),
Builder\Block::make('person')
->schema([
TextInput::make('name')
->label('Имя')
->required()
->maxLength(255),
FileUpload::make('photo')
->label('Фотография')
->image()
->disk('public')
->directory('images')
->imageEditor(),
Forms\Components\Repeater::make('info')->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('column')
->required()
->maxLength(255),
TextInput::make('content')
->required()
->maxLength(255),
]),
])->minItems(1),
]),
Builder\Block::make('stepper')
->schema([
TextInput::make('step_name')
->label('Название шага')
->required()
->maxLength(255),
Forms\Components\Repeater::make('steps')->schema([
TextInput::make('title')
->required()
->maxLength(255)->columnSpanFull(),
RichEditor::make('content')->required(),
])->minItems(1),
]),
Builder\Block::make('images')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Слайдер изображений'),
Builder\Block::make('image')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Изображение'),
Builder\Block::make('video')
->schema([
TextInput::make('mime')->readOnly(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'video/mp4',
'video/quicktime',
'video/x-msvideo',
'video/x-ms-wmv',
'video/avi',
'video/webm',
'video/ogg',
'video/3gpp',
'video/3gpp2',
'video/x-m4v',
])
->disk('public')
->directory('videos')
->afterStateUpdated(fn (callable $set, $state) => $set('mime', $state?->getMimeType())),
]),
Builder\Block::make('postsList')
->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('count')
->label('Количество запией')
->integer(),
Select::make('category')
->options(Category::all()->pluck('title', 'id'))
]),
])->label('Список новостей'),
])
->collapsed()
->blockNumbers(false)
->collapsible()
->addActionLabel('Добавить новый блок'),
])->minItems(1),
]),
Builder\Block::make('images')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Слайдер изображений'),
Builder\Block::make('image')
->schema([
FileUpload::make('url')
->label('Изображение(-я)')
->image()
->multiple()
->reorderable()
->maxFiles(5)
->disk('public')
->directory('images')
->imageEditor()
->required(),
TextInput::make('alt')
->label('Описание')
->placeholder('Необязяательно')
])->label('Изображение'),
Builder\Block::make('video')
->schema([
TextInput::make('mime')->readOnly(),
TextInput::make('title')
->required()
->maxLength(255)
->autofocus(),
FileUpload::make('path')
->required()
->acceptedFileTypes([
'video/mp4',
'video/quicktime',
'video/x-msvideo',
'video/x-ms-wmv',
'video/avi',
'video/webm',
'video/ogg',
'video/3gpp',
'video/3gpp2',
'video/x-m4v',
])
->disk('public')
->directory('videos')
->afterStateUpdated(fn (callable $set, $state) => $set('mime', $state?->getMimeType())),
]),
Builder\Block::make('postsList')
->schema([
Forms\Components\Grid::make(2)->schema([
TextInput::make('count')
->label('Количество запией')
->integer(),
Select::make('category')
->options(Category::all()->pluck('title', 'id'))
]),
])->label('Список новостей'),
Builder\Block::make('postItem')
->schema([
Select::make('post')
->options(Post::query()->where('status', PostStatus::PUBLISHED)->pluck('title', 'id'))
->searchable()
->required(),
])->label('Новость'),
Builder\Block::make('pageItem')
->schema([
Select::make('page')
->options(Page::query()->where('title', '!=' , null)->where('is_visible', true)->pluck('title', 'id'))
->searchable()
->required(),
])->label('Страница'),
Builder\Block::make('customForm')
->schema([
Select::make('form')
->options(CustomForm::query()->where('status', CustomFormStatus::PUBLISHED)->pluck('title', 'form_id'))
->searchable()
->required(),
])->label('Форма'),
Builder\Block::make('pageResourceList')
->schema([
Select::make('resource')
->options(PageReferenceList::query()->where('is_active', true)->pluck('title', 'slug'))
->searchable()
->required(),
])->label('Ресурсы'),
])
->collapsed()
->blockNumbers(false)
->collapsible()
->required()
->blockPickerColumns(3)
->blockPickerWidth('2xl')
->addActionLabel('Добавить новый блок'),
]),
]),
])
]);
}
public static function table(Table $table): Table
@@ -70,7 +462,6 @@ class FacultyResource extends Resource
public static function getRelations(): array
{
return [
DepartmentsRelationManager::class,
WorkersRelationManager::class
];
}
@@ -29,20 +29,15 @@ class CreateFaculty extends CreateRecord
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
} $image = ($data['preview'] !== null) ? $data['preview'] : null;
}
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -68,22 +63,6 @@ class CreateFaculty extends CreateRecord
return $data;
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function getDataFromBlocks($block) : string
{
@@ -28,41 +28,19 @@ class EditFaculty extends EditRecord
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
$image = ($this->record->preview !== null) ? $this->record->preview : null;
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -29,20 +29,15 @@ class CreateLibraryNews extends CreateRecord
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
} $image = ($data['preview'] !== null) ? $data['preview'] : null;
}
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -68,22 +63,6 @@ class CreateLibraryNews extends CreateRecord
return $data;
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function getDataFromBlocks($block) : string
{
@@ -28,41 +28,18 @@ class EditLibraryNews extends EditRecord
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
$image = ($this->record->preview !== null) ? $this->record->preview : null;
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -29,20 +29,15 @@ class CreateVirtualExhibition extends CreateRecord
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
} $image = ($data['preview'] !== null) ? $data['preview'] : null;
}
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -68,22 +63,6 @@ class CreateVirtualExhibition extends CreateRecord
return $data;
}
private function getBlockBySeoActiveState(string $name, array $content) : array|null
{
$data = [];
foreach ($content as $block) {
if ($block['type'] === $name) {
$data[] = $block;
}
}
$block = null;
foreach ($data as $item) {
if ($item['data']['seo_active'] === true) {
$block = $item;
}
}
return $block;
}
private function getDataFromBlocks($block) : string
{
@@ -48,21 +48,15 @@ class EditVirtualExhibition extends EditRecord
private function generateSeo(array $data) : array
{
$title = $data['title'];
$rowData = $this->getBlockBySeoActiveState('paragraph', $data['content']);
if ($rowData === null) {
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
}
$rowData = $this->getFirstBlockByName('paragraph', $data['content']);
if ($rowData !== null) {
$description = strip_tags($rowData['data']['content']);
} else {
$description = null;
}
$image = ($this->record->preview !== null) ? $this->record->preview : null;
return [
'title' => $title,
'description' => Str::limit(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), 160),
'image' => $image,
];
}
@@ -134,6 +134,8 @@ class ClientAdditionalEducationController extends Controller
$breadcrumbs = null;
}
return Inertia::render('Client/Additional-educations/Show', compact('additionalEducation', 'breadcrumbs'));
$seo = $additionalEducation->seo;
return Inertia::render('Client/Additional-educations/Show', compact('additionalEducation', 'breadcrumbs', 'seo'));
}
}
@@ -27,7 +27,9 @@ class ClientDepartmentController extends Controller
->with(['faculty', 'workers.userDetail', 'teachers.userDetail', 'programs.directionStudy'])
->first());
$directions = $this->groupProgramsByDirection($department->programs);
return Inertia::render('Client/Departments/Show', compact('department', 'departments', 'directions'));
$seo = $department->seo;
return Inertia::render('Client/Departments/Show', compact('department', 'departments', 'directions', 'seo'));
}
@@ -19,6 +19,7 @@ class ClientDivisionController extends Controller
{
$divisions = DivisionResource::collection(Division::query()->where('is_active', true)->get());
$division = new DivisionResource(Division::with('workers.userDetail')->where('is_active', true)->where('slug', $slug)->first());
return Inertia::render('Client/Divisions/Show', compact('divisions', 'division'));
$seo = $division->seo;
return Inertia::render('Client/Divisions/Show', compact('divisions', 'division', 'seo'));
}
}
@@ -16,10 +16,12 @@ class ClientFacultyController extends Controller
return Inertia::render('Client/Faculties/Index', compact('faculties'));
}
public function show(string $slug)
{
$faculties = FacultyResource::collection(Faculty::query()->where('is_active', true)->get());
$faculty = new FullFacultyResource(Faculty::where('slug', $slug)->where('is_active', true)->with(['departments.faculty', 'workers.userDetail'])->first());
return Inertia::render('Client/Faculties/Show', compact('faculty', 'faculties'));
$seo = $faculty->seo;
return Inertia::render('Client/Faculties/Show', compact('faculty', 'faculties', 'seo'));
}
}
@@ -119,7 +119,9 @@ class ClientProgramController extends Controller
$formsEdu = $formsEducational->mapWithKeys(function ($formEducational) {
return [$formEducational->value => $formEducational->getLabel()];
});
return Inertia::render('Client/Programs/Show', compact('program', 'formsEdu'));
$seo = $this->seo;
return Inertia::render('Client/Programs/Show', compact('program', 'formsEdu', 'seo'));
}
private function getAdmissionCampaignName() : string
@@ -0,0 +1,63 @@
<?php
namespace App\Http\Controllers;
use App\Enums\PostStatus;
use App\Models\Page;
use App\Models\Post;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
class GenerateSitemapController extends Controller
{
public function index()
{
$sitemap = Sitemap::create();
$this->generatePages($sitemap);
$this->generatePosts($sitemap);
$sitemap->writeToFile(public_path('sitemap.xml'));
}
protected function generatePages(Sitemap $sitemap)
{
$pages = Page::query()
->where('is_visible', true)
->where('code', 200)
->get();
$this->addUrlsToSitemap($sitemap, $pages, function($page) {
return [
'path' => "/{$page->path}",
'lastModificationDate' => $page->updated_at,
'priority' => 0.5,
];
});
}
protected function generatePosts(Sitemap $sitemap)
{
$posts = Post::query()
->where('status', PostStatus::PUBLISHED)
->get();
$this->addUrlsToSitemap($sitemap, $posts, function($post) {
return [
'path' => "/news/{$post->slug}",
'lastModificationDate' => $post->updated_at,
'priority' => 0.5,
];
});
}
protected function addUrlsToSitemap(Sitemap $sitemap, $items, callable $callback)
{
foreach ($items as $item) {
$urlData = $callback($item);
$sitemap->add(Url::create($urlData['path'])
->setLastModificationDate($urlData['lastModificationDate'])
->setPriority($urlData['priority']));
}
}
}
@@ -14,8 +14,10 @@ use App\Models\AdditionalEducation;
use App\Models\EducationalGroup;
use App\Models\EducationalProgram;
use App\Models\Event;
use App\Models\Faculty;
use App\Models\Page;
use App\Models\Post;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
@@ -43,6 +45,8 @@ class SearchController extends Controller
->add(AdditionalEducation::where('is_active', '=', true), 'title')
->add(EducationalGroup::with('schedules'), 'title')
->add(EducationalProgram::where('status', '=', true)->whereHas('admission_plans'), 'name')
->add(Faculty::where('is_active', '=', true), 'title')
->add(User::whereHas('userDetail'), ['name', 'userDetail.education', 'userDetail.awards', 'userDetail.publications',])
->beginWithWildcard()
->orderByRelevance()
->includeModelType()
+1 -1
View File
@@ -31,7 +31,7 @@ class AppServiceProvider extends ServiceProvider
setlocale(LC_TIME, 'ru_RU.UTF-8');
Carbon::setLocale(config('app.locale'));
Model::preventLazyLoading(!app()->isProduction());
URL::forceScheme('https');
// URL::forceScheme('https');
self::registerFilamentNavigationGroups();
}
+1
View File
@@ -23,6 +23,7 @@
"nesbot/carbon": "^2.71",
"protonemedia/laravel-cross-eloquent-search": "^3.4",
"pxlrbt/filament-excel": "^2.3",
"spatie/laravel-sitemap": "^7.2",
"symfony/filesystem": "^6.3",
"tightenco/ziggy": "^1.0",
"vkcom/vk-php-sdk": "^5.131",
Generated
+454 -3
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "4ec8fd7d71eed92d6bd7cd1106725919",
"content-hash": "54c73bafbbc855a5a9df56d74018c728",
"packages": [
{
"name": "anourvalar/eloquent-serialize",
@@ -4859,6 +4859,60 @@
},
"time": "2024-08-07T15:39:19+00:00"
},
{
"name": "nicmart/tree",
"version": "0.8.0",
"source": {
"type": "git",
"url": "https://github.com/nicmart/Tree.git",
"reference": "8d02952acc9779a2c14f7a9c4ac1650c3dacb545"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nicmart/Tree/zipball/8d02952acc9779a2c14f7a9c4ac1650c3dacb545",
"reference": "8d02952acc9779a2c14f7a9c4ac1650c3dacb545",
"shasum": ""
},
"require": {
"php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.31.0",
"ergebnis/license": "^2.4.0",
"ergebnis/php-cs-fixer-config": "^6.13.0",
"fakerphp/faker": "^1.23.0",
"infection/infection": "~0.26.19",
"phpunit/phpunit": "^9.6.14",
"psalm/plugin-phpunit": "~0.18.4",
"vimeo/psalm": "^5.16.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Tree\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolò Martini",
"email": "nicmartnic@gmail.com"
},
{
"name": "Andreas Möller",
"email": "am@localheinz.com"
}
],
"description": "A basic but flexible php tree data structure and a fluent tree builder implementation.",
"support": {
"issues": "https://github.com/nicmart/Tree/issues",
"source": "https://github.com/nicmart/Tree/tree/0.8.0"
},
"time": "2023-12-02T13:24:56+00:00"
},
{
"name": "nikic/php-parser",
"version": "v5.2.0",
@@ -6329,6 +6383,74 @@
],
"time": "2022-12-17T21:53:22+00:00"
},
{
"name": "spatie/browsershot",
"version": "4.3.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/browsershot.git",
"reference": "601f2758191d8c46b2ea587eea935a87da4f39e8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/browsershot/zipball/601f2758191d8c46b2ea587eea935a87da4f39e8",
"reference": "601f2758191d8c46b2ea587eea935a87da4f39e8",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"ext-json": "*",
"php": "^8.2",
"spatie/temporary-directory": "^2.0",
"symfony/process": "^6.0|^7.0"
},
"require-dev": {
"pestphp/pest": "^1.20",
"spatie/image": "^3.6",
"spatie/pdf-to-text": "^1.52",
"spatie/phpunit-snapshot-assertions": "^4.2.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Browsershot\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://github.com/freekmurze",
"role": "Developer"
}
],
"description": "Convert a webpage to an image or pdf using headless Chrome",
"homepage": "https://github.com/spatie/browsershot",
"keywords": [
"chrome",
"convert",
"headless",
"image",
"pdf",
"puppeteer",
"screenshot",
"webpage"
],
"support": {
"source": "https://github.com/spatie/browsershot/tree/4.3.0"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2024-08-22T09:14:07+00:00"
},
{
"name": "spatie/color",
"version": "1.6.0",
@@ -6388,6 +6510,74 @@
],
"time": "2024-09-20T14:00:15+00:00"
},
{
"name": "spatie/crawler",
"version": "8.2.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/crawler.git",
"reference": "c659f2fe4954249755990e42394a14d6d847a0a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/crawler/zipball/c659f2fe4954249755990e42394a14d6d847a0a7",
"reference": "c659f2fe4954249755990e42394a14d6d847a0a7",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^7.3",
"guzzlehttp/psr7": "^2.0",
"illuminate/collections": "^10.0|^11.0",
"nicmart/tree": "^0.8.0",
"php": "^8.1",
"spatie/browsershot": "^3.45|^4.0",
"spatie/robots-txt": "^2.0",
"symfony/dom-crawler": "^6.0|^7.0"
},
"require-dev": {
"pestphp/pest": "^2.0",
"spatie/ray": "^1.37"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Crawler\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be"
}
],
"description": "Crawl all internal links found on a website",
"homepage": "https://github.com/spatie/crawler",
"keywords": [
"crawler",
"link",
"spatie",
"website"
],
"support": {
"issues": "https://github.com/spatie/crawler/issues",
"source": "https://github.com/spatie/crawler/tree/8.2.3"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2024-07-31T10:46:19+00:00"
},
{
"name": "spatie/eloquent-sortable",
"version": "4.4.0",
@@ -6663,6 +6853,79 @@
],
"time": "2024-06-22T23:04:52+00:00"
},
{
"name": "spatie/laravel-sitemap",
"version": "7.2.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-sitemap.git",
"reference": "6d3d7637690a9710456a01bacabf5088f93ffe11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-sitemap/zipball/6d3d7637690a9710456a01bacabf5088f93ffe11",
"reference": "6d3d7637690a9710456a01bacabf5088f93ffe11",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^7.8",
"illuminate/support": "^10.0|^11.0",
"nesbot/carbon": "^2.71|^3.0",
"php": "^8.2",
"spatie/crawler": "^8.0.1",
"spatie/laravel-package-tools": "^1.16.1",
"symfony/dom-crawler": "^6.3.4|^7.0"
},
"require-dev": {
"mockery/mockery": "^1.6.6",
"orchestra/testbench": "^8.14|^9.0",
"pestphp/pest": "^2.24",
"spatie/pest-plugin-snapshots": "^2.1",
"spatie/phpunit-snapshot-assertions": "^5.1.2",
"spatie/temporary-directory": "^2.2"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\Sitemap\\SitemapServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Spatie\\Sitemap\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Create and generate sitemaps with ease",
"homepage": "https://github.com/spatie/laravel-sitemap",
"keywords": [
"laravel-sitemap",
"spatie"
],
"support": {
"source": "https://github.com/spatie/laravel-sitemap/tree/7.2.1"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
}
],
"time": "2024-05-21T12:31:34+00:00"
},
{
"name": "spatie/laravel-tags",
"version": "4.6.1",
@@ -6815,6 +7078,66 @@
],
"time": "2024-07-24T14:26:27+00:00"
},
{
"name": "spatie/robots-txt",
"version": "2.2.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/robots-txt.git",
"reference": "31763e5ca23fb0efa6dc6b700beb5ebfeab89432"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/robots-txt/zipball/31763e5ca23fb0efa6dc6b700beb5ebfeab89432",
"reference": "31763e5ca23fb0efa6dc6b700beb5ebfeab89432",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"phpunit/phpunit": "^9.0|^10.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Robots\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brent Roose",
"email": "brent@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Determine if a page may be crawled from robots.txt and robots meta tags",
"homepage": "https://github.com/spatie/robots-txt",
"keywords": [
"robots-txt",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/robots-txt/issues",
"source": "https://github.com/spatie/robots-txt/tree/2.2.3"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2024-10-22T08:17:03+00:00"
},
{
"name": "spatie/shiki-php",
"version": "2.0.0",
@@ -6879,6 +7202,67 @@
],
"time": "2024-02-19T09:00:59+00:00"
},
{
"name": "spatie/temporary-directory",
"version": "2.2.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/temporary-directory.git",
"reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/temporary-directory/zipball/76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a",
"reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a",
"shasum": ""
},
"require": {
"php": "^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\TemporaryDirectory\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alex Vanderbist",
"email": "alex@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Easily create, use and destroy temporary directories",
"homepage": "https://github.com/spatie/temporary-directory",
"keywords": [
"php",
"spatie",
"temporary-directory"
],
"support": {
"issues": "https://github.com/spatie/temporary-directory/issues",
"source": "https://github.com/spatie/temporary-directory/tree/2.2.1"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2023-12-25T11:46:58+00:00"
},
{
"name": "symfony/console",
"version": "v6.4.12",
@@ -7105,6 +7489,73 @@
],
"time": "2024-04-18T09:32:20+00:00"
},
{
"name": "symfony/dom-crawler",
"version": "v7.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "794ddd5481ba15d8a04132c95e211cd5656e09fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/794ddd5481ba15d8a04132c95e211cd5656e09fb",
"reference": "794ddd5481ba15d8a04132c95e211cd5656e09fb",
"shasum": ""
},
"require": {
"masterminds/html5": "^2.6",
"php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"symfony/css-selector": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\DomCrawler\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Eases DOM navigation for HTML and XML documents",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/dom-crawler/tree/v7.1.6"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-10-25T15:11:02+00:00"
},
{
"name": "symfony/error-handler",
"version": "v6.4.10",
@@ -11802,13 +12253,13 @@
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
"php": "^8.1",
"ext-curl": "*"
},
"platform-dev": [],
"platform-dev": {},
"plugin-api-version": "2.6.0"
}
+57
View File
@@ -0,0 +1,57 @@
<?php
use GuzzleHttp\RequestOptions;
use Spatie\Sitemap\Crawler\Profile;
return [
/*
* These options will be passed to GuzzleHttp\Client when it is created.
* For in-depth information on all options see the Guzzle docs:
*
* http://docs.guzzlephp.org/en/stable/request-options.html
*/
'guzzle_options' => [
/*
* Whether or not cookies are used in a request.
*/
RequestOptions::COOKIES => true,
/*
* The number of seconds to wait while trying to connect to a server.
* Use 0 to wait indefinitely.
*/
RequestOptions::CONNECT_TIMEOUT => 10,
/*
* The timeout of the request in seconds. Use 0 to wait indefinitely.
*/
RequestOptions::TIMEOUT => 10,
/*
* Describes the redirect behavior of a request.
*/
RequestOptions::ALLOW_REDIRECTS => false,
],
/*
* The sitemap generator can execute JavaScript on each page so it will
* discover links that are generated by your JS scripts. This feature
* is powered by headless Chrome.
*/
'execute_javascript' => false,
/*
* The package will make an educated guess as to where Google Chrome is installed.
* You can also manually pass its location here.
*/
'chrome_binary_path' => null,
/*
* The sitemap generator uses a CrawlProfile implementation to determine
* which urls should be crawled for the sitemap.
*/
'crawl_profile' => Profile::class,
];
@@ -17,11 +17,13 @@ import ProgramTitle from "@/Components/BuilderUi/AdditionalEducationPrograms/Pro
import ProgramBuilder from "@/Components/BuilderUi/AdditionalEducationPrograms/ProgramBuilder.vue";
import AdditionalEducationProgramItemBreadcrumbs
from "@/Components/BuilderUi/AdditionalEducationPrograms/AdditionalEducationProgramItemBreadcrumbs.vue";
import AppHead from "@/Components/AppHead.vue";
export default {
name: "Show",
components: {
AppHead,
AdditionalEducationProgramItemBreadcrumbs,
ProgramBuilder,
ProgramTitle,
@@ -34,7 +36,7 @@ export default {
AdminIndexHeader,
ClientPost,
ClientPostFilter,
ClientFooterDown, ClientScrollTimeline, Link, FsLightbox, Head},
ClientFooterDown, ClientScrollTimeline, Link, Head},
data() {
return {
@@ -45,7 +47,10 @@ export default {
type: Object,
},
breadcrumbs: {
type: Object
type: Object,
},
seo: {
type: Object,
}
},
methods: {
@@ -65,10 +70,10 @@ export default {
</script>
<template>
<Head>
<title>Образовательная программа</title>
<meta name="description" content="Your page description">
</Head>
<AppHead
:title="seo.title"
:description="seo.description"
/>
<MainPageNavBar class="border-b" :sections="$page.props.navigation"></MainPageNavBar>
<div class="flex flex-col h-screen">
+13 -5
View File
@@ -1,9 +1,12 @@
<template>
<Head>
<title>{{ department.data.title }}</title>
<meta name="description" content="Your page description">
</Head>
<MainPageNavBar class="border-b" :sections="$page.props.navigation"></MainPageNavBar>
<AppHead
:title="seo.title"
:description="seo.description"
/>
<MainPageNavBar class="border-b" :sections="$page.props.navigation" />
<div class="flex flex-col h-screen justify-between">
<div class="relative mb-auto mx-auto mt-[67px] max-w-screen-xl px-4 py-10 md:flex md:flex-row md:py-10">
@@ -166,6 +169,7 @@ import DepartmentBuilder from "@/Components/BuilderUi/Departments/DepartmentBuil
import DepartmentBackButton from "@/Components/BuilderUi/Departments/DepartmentBackButton.vue";
import MainPageNavBar from "@/Navbars/MainPageNavbar.vue";
import DepartmentItemBreadcrumbs from "@/Components/BuilderUi/Departments/DepartmentItemBreadcrumbs.vue";
import AppHead from "@/Components/AppHead.vue";
export default {
@@ -187,9 +191,13 @@ export default {
directions: {
type: Object
},
seo: {
type: Object
}
},
components: {
AppHead,
DepartmentItemBreadcrumbs,
MainPageNavBar,
DepartmentBackButton,
+9 -6
View File
@@ -1,10 +1,8 @@
<template>
<Head>
<title>{{ division.data.title }}</title>
<meta name="description" content="Your page description">
</Head>
<AppHead
:title="seo.title"
:description="seo.description"
/>
<div class="flex flex-col h-screen">
<MainPageNavBar class="border-b" :sections="$page.props.navigation"></MainPageNavBar>
@@ -142,6 +140,7 @@ import axios from "axios";
import MainPageNavBar from "@/Navbars/MainPageNavbar.vue";
import DivisionBuilder from "@/Components/BuilderUi/Divisions/DivisionBuilder.vue";
import DivisionItemBreadcrumbs from "@/Components/BuilderUi/Divisions/DivisionItemBreadcrumbs.vue";
import AppHead from "@/Components/AppHead.vue";
export default {
@@ -160,9 +159,13 @@ export default {
divisions: {
type: Object
},
seo: {
type: Object,
}
},
components: {
AppHead,
DivisionItemBreadcrumbs,
DivisionBuilder,
MainPageNavBar,
+9 -7
View File
@@ -1,11 +1,8 @@
<template>
<Head>
<title>{{ faculty.data.title }}</title>
<meta name="description" content="Your page description">
</Head>
<AppHead
:title="seo.title"
:description="seo.description"
/>
<div class="flex flex-col h-screen justify-between">
<MainPageNavBar class="border-b" :sections="$page.props.navigation"></MainPageNavBar>
@@ -161,6 +158,7 @@ import PostBuilder from "@/Components/BuilderUi/Posts/PostBuilder.vue";
import FacultyBuilder from "@/Components/BuilderUi/Faculties/FacultyBuilder.vue";
import MainPageNavBar from "@/Navbars/MainPageNavbar.vue";
import FacultyItemBreadcrumbs from "@/Components/BuilderUi/Faculties/FacultyItemBreadcrumbs.vue";
import AppHead from "@/Components/AppHead.vue";
export default {
@@ -179,9 +177,13 @@ export default {
faculties: {
type: Object
},
seo: {
type: Object,
}
},
components: {
AppHead,
FacultyItemBreadcrumbs,
MainPageNavBar,
FacultyBuilder,
+1
View File
@@ -70,6 +70,7 @@ export default {
}}
</script>
<template>
<AppHead
:title="seo.title"
:description="seo.description"
+9 -4
View File
@@ -19,11 +19,13 @@ import ProgramTitle from "@/Components/BuilderUi/AdditionalEducationPrograms/Pro
import ProgramBuilder from "@/Components/BuilderUi/AdditionalEducationPrograms/ProgramBuilder.vue";
import ProgramBackButton from "@/Components/BuilderUi/Programs/ProgramBackButton.vue";
import BaseBuilder from "@/Components/BaseComponents/BaseBuilderUi/BaseBuilder.vue";
import AppHead from "@/Components/AppHead.vue";
export default {
name: "Show",
components: {
AppHead,
BaseBuilder,
ProgramBackButton, ProgramBuilder, ProgramTitle, AdditionalEducationProgramItemBreadcrumbs,
ProgramItemBreadcrumbs,
@@ -53,6 +55,9 @@ export default {
},
formsEdu: {
type: Array
},
seo: {
type: Object,
}
},
@@ -73,10 +78,10 @@ export default {
</script>
<template>
<Head>
<title>Образовательная программа</title>
<meta name="description" content="Your page description">
</Head>
<AppHead
:title="seo.title"
:description="seo.description"
/>
<MainPageNavBar class="border-b" :sections="$page.props.navigation"></MainPageNavBar>
+7 -4
View File
@@ -15,6 +15,7 @@ use App\Http\Controllers\ClientVacantPositionController;
use App\Http\Controllers\ClientVirtualExhibitionController;
use App\Http\Controllers\ClientWidgetFormController;
use App\Http\Controllers\EducationalProgramController;
use App\Http\Controllers\GenerateSitemapController;
use App\Http\Controllers\LinkToolController;
use App\Http\Controllers\MainController;
use App\Http\Controllers\PageController;
@@ -25,18 +26,20 @@ use App\Http\Controllers\UpdateEduDataApiController;
use App\Http\Controllers\UpdateViconDataApi;
use App\Http\Controllers\VkAuthController;
use App\Http\Controllers\VkPostController;
use App\Models\Post;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\SitemapGenerator;
use Spatie\Sitemap\Tags\Url;
Route::middleware('signed')->get('invitation/{invitation}/accept', \App\Livewire\AcceptInvitation::class)
->name('invitation.accept');
Route::middleware('access-check')->group(function () {
Route::get('/generate-sitemap', [GenerateSitemapController::class, 'index']);
// Route::get('/dashboard/schedule/create', function () {
// return Inertia::render('Dashboard/CreateSchedule');
// });
Route::middleware('access-check')->group(function () {
// Главная страница
Route::get('/', [MainController::class, 'index'])->name('index');