# Визуальная кастомизация страниц — Анализ и план реализации > **Дата:** 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 ``` **Плюсы:** - ✅ Минимальные изменения в архитектуре - ✅ Использует существующую инфраструктуру `settings` - ✅ Легко масштабировать (добавить новые поля в JSON) - ✅ Не требует миграций БД - ✅ Работает для **обоих типов страниц** (нужно только передать `settings` в Inertia) **Минусы:** - ❌ Ограниченный набор стилей (только то, что предусмотрено в UI) - ❌ Нужно менять все Builder-блоки для поддержки наследования стилей --- ### Решение 2: CSS Custom Properties (CSS Variables) **Концепция:** Хранить CSS-переменные в `settings`, применять через inline `
``` **Плюсы:** - ✅ Гибкость — можно задать **любое** CSS-свойство - ✅ Каскадное применение — переменные наследуются вниз - ✅ Не нужно менять все Builder-блоки (применяются глобально) - ✅ Легко реализовать в админке (ключ-значение форма) **Минусы:** - ❌ Требует знания CSS у контент-менеджеров (или ограниченный набор в UI) - ❌ Могут быть конфликты с Tailwind классами - ❌ Сложнее валидировать значения --- ### Решение 3: Page Themes / Templates System **Концепция:** Создать систему **тем** — предустановленных наборов стилей. **Структура данных:** **Таблица `page_themes`:** ```sql id | name | description | styles (JSON) | is_active 1 | Default | Стандартная тема | {...} | true 2 | Compact | Компактная | {...} | false 3 | Spacious | Просторная | {...} | false ``` **`pages` таблица — новые колонки:** ```sql theme_id (FK -> page_themes) custom_overrides (JSON) — индивидуальные переопределения ``` **Пример `styles` в теме:** ```json { "typography": { "font_family": "Inter", "title_sizes": { "h1": "3xl", "h2": "2xl", "h3": "xl" }, "body_size": "base", "line_height": "relaxed" }, "spacing": { "container": { "max_width": "screen-xl", "px": "4", "py": "10" }, "content_gap": "space-y-5" }, "colors": { "background": "white", "text": "gray-900", "accent": "primary" }, "borders": { "radius": "rounded-lg", "shadow": "shadow-sm" } } ``` **Filament админка:** - CRUD для `PageTheme` (создание/редактирование тем) - В `PageForm`: `Select::make('theme_id')->relationship('theme', 'name')` - Опционально: overrides для конкретной страницы **Frontend:** ```vue ``` **Плюсы:** - ✅ **Масштабируемость** — одна тема применяется к множеству страниц - ✅ **Безопасность** — админ не сломает стили (выбирает из готовых) - ✅ **A/B тестирование** — легко менять темы - ✅ Разделение ответственности: дизайнер создаёт темы, контент-менеджер выбирает **Минусы:** - ❌ **Сложность реализации** — новая таблица, CRUD, UI для тем - ❌ Требует больше времени на разработку - ❌ Нужно менять `PageResource`, `RenderPageAction`, `Page.vue` --- ### Решение 4: Custom CSS per Page (Полная свобода) **Концепция:** Позволить админу писать **произвольный CSS** для страницы. **Структура данных:** ```json { "visual": { "custom_css": "#page-area h1 { font-size: 2.5rem; color: #2D4191; }\n#page-area p { line-height: 1.8; }" } } ``` **Frontend:** ```vue