# Визуальная кастомизация страниц — Анализ и план реализации
> **Дата:** 7 апреля 2026 г.
> **Контекст:** Запрос на функционал изменения визуала страниц через админку (отступы, шрифты, размеры, цвета и т.д.)
---
## 📊 Текущая архитектура страниц
В проекте существуют **два типа страниц**:
### Тип A: Database-driven страницы (Page Builder)
| Параметр | Значение |
|----------|----------|
| **Создаются** | Через Filament админку |
| **Хранение** | JSON в колонке `content` таблицы `pages` |
| **Рендеринг** | Универсальный `Page.vue` → `Builder` компонент → динамический рендер блоков |
| **Стилизация** | Hardcoded Tailwind классы в блоках (`HeadingBlock.vue`, `ParagraphBlock.vue`, и т.д.) |
| **Настройки** | Колонка `settings` (JSON) — только **логические флаги** (скрыть breadcrumbs, навигацию и т.д.) |
**Ключевые файлы:**
- Model: `app/Containers/AppStructure/Models/Page.php`
- Controller: `app/Containers/AppStructure/UI/WEB/Controllers/PageController.php`
- Action: `app/Containers/AppStructure/Actions/RenderPageAction.php`
- Vue: `resources/js/Pages/Page.vue`
- Builder: `resources/js/componentss/shared/builder/pageBuilder/Builder.vue`
- Filament Form: `app/Filament/Components/Forms/PageForm.php`
- Filament Builder: `app/Filament/Components/Forms/ItemForm/Pages/ContentBuilderItem.php`
### Тип B: Code-driven страницы (Hardcoded Vue компоненты)
| Параметр | Значение |
|----------|----------|
| **Создаются** | Как `.vue` файлы в `resources/js/Pages/` |
| **Примеры** | `Main.vue` (главная), страницы Dashboard |
| **Стилизация** | Tailwind классы напрямую в template |
| **Авто-регистрация** | `RegisterApplicationRoutesTask` создаёт запись в `pages` с `is_registered = true` |
**Ключевые файлы:**
- Task: `app/Containers/AppStructure/Tasks/RegisterApplicationRoutesTask.php`
- Middleware: `app/Ship/Middleware/AccessCheck.php`
- Пример: `resources/js/Pages/Main.vue`
### Текущая структура `pages.settings`
```json
{
"hide_page_sub_section_links": false,
"hide_page_navigate_links": false,
"hide_breadcrumbs": false,
"form": {
"id": "form_id",
"title": "Заголовок",
"description": "Описание",
"button": "Текст кнопки"
}
}
```
### Текущая структура `pages` таблицы
| Колонка | Тип | Описание |
|---------|-----|----------|
| `id` | bigint | Primary key |
| `title` | string(255) | Заголовок страницы |
| `content` | longText (JSON) | Builder блоки |
| `slug` | string(255) | URL сегмент |
| `path` | string | Полный URL путь |
| `is_registered` | boolean | true = авто-регистрация из кода |
| `is_visible` | boolean | Видимость |
| `searchable` | boolean | Индексация в поиске |
| `is_url` | boolean | Редирект на внешний URL |
| `code` | integer | HTTP статус (200, 404, 500) |
| `sub_section_id` | bigint FK | Связь с подразделом |
| `settings` | longText (JSON) | Настройки отображения |
| `icon` | string | Heroicon для навигации |
| `search_data` | longText | Текст для поиска |
---
## 🎯 Проблема
Сейчас **нет возможности** через админку менять визуальные параметры страниц:
- ❌ Отступы (padding, margin)
- ❌ Размер шрифта
- ❌ Шрифт (font-family)
- ❌ Цвета
- ❌ Максимальная ширина контента
- ❌ И другие CSS-свойства
Все стили **захардкожены** в Vue компонентах и блоках билдера.
---
## 💡 Решения (от простого к сложному)
### Решение 1: Расширение `settings` JSON (Рекомендуемое)
**Концепция:** Добавить в существующую колонку `pages.settings` секцию `visual` с визуальными настройками.
**Структура данных:**
```json
{
"hide_page_sub_section_links": false,
"hide_page_navigate_links": false,
"hide_breadcrumbs": false,
"form": { ... },
"visual": {
"typography": {
"font_family": "Inter",
"title_size": "2xl",
"body_size": "base",
"line_height": "normal"
},
"spacing": {
"container_padding_top": "10",
"container_padding_bottom": "10",
"container_padding_x": "4",
"content_gap": "5"
},
"layout": {
"max_width": "screen-xl",
"sidebar_position": "left"
},
"colors": {
"background": "white",
"text": "gray-900"
}
}
}
```
**Backend (Filament Form) — пример добавления в PageForm.php:**
```php
Section::make('Визуальные настройки')
->description('Настройка внешнего вида страницы')
->collapsible()
->schema([
Select::make('visual.typography.font_family')
->label('Шрифт')
->options([
'Inter' => 'Inter (по умолчанию)',
'Roboto' => 'Roboto',
'Open Sans' => 'Open Sans',
'Montserrat' => 'Montserrat',
])
->default('Inter'),
Select::make('visual.typography.title_size')
->label('Размер заголовка')
->options([
'xl' => 'XL (маленький)',
'2xl' => '2XL (стандарт)',
'3xl' => '3XL (большой)',
'4xl' => '4XL (очень большой)',
])
->default('2xl'),
Select::make('visual.spacing.container_padding_top')
->label('Отступ сверху')
->options([
'0' => '0',
'4' => '16px',
'6' => '24px',
'10' => '40px',
])
->default('10'),
]);
```
**Frontend (Page.vue) — пример применения:**
```vue