🎨 Добавлен полный редактор стилей и поле image_url для туров

 Новые функции:
- Поле image_url в модели туров для изменения изображений через админ-панель
- Расширенная модель настроек сайта с категориями: colors, typography, images, effects, layout
- Динамический CSS генератор на основе настроек (/dynamic-styles.css)
- API для управления настройками сайта (/api/site-settings)

🎯 Редактор стилей:
- Управление цветами (основные, акцентные, текст, фон)
- Настройка типографики (шрифты, размеры, межстрочный интервал)
- Управление изображениями (фоны, логотипы, фавикон)
- Эффекты (прозрачность, тени, размытие, скругления)
- Макет (высота секций, размеры контейнеров)
- Пользовательский CSS код

🛠️ Техническая реализация:
- SiteSettingsHelper с кешированием для производительности
- CSS переменные для динамического изменения стилей
- Автоматическая миграция базы данных
- Интеграция с AdminJS для удобного управления
- Загрузка настроек в шаблоны для доступности

📊 База данных:
- Расширена таблица site_settings (добавлено поле category)
- Новые типы настроек: color, file
- 27 предустановленных настроек для полного контроля над дизайном
- Автоматическое применение миграций при старте приложения
This commit is contained in:
2025-11-29 22:03:00 +09:00
parent a461fea9d9
commit ed871fc4d1
8 changed files with 528 additions and 28 deletions

View File

@@ -0,0 +1,78 @@
-- Миграция для добавления полей image_url и расширения настроек сайта
-- Добавление поля image_url в таблицу routes (если его нет)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'routes' AND column_name = 'image_url') THEN
ALTER TABLE routes ADD COLUMN image_url VARCHAR(255);
END IF;
END $$;
-- Добавление поля category в таблицу site_settings (если его нет)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'site_settings' AND column_name = 'category') THEN
ALTER TABLE site_settings ADD COLUMN category VARCHAR(50) DEFAULT 'general';
END IF;
END $$;
-- Обновление типов в таблице site_settings
DO $$
BEGIN
-- Удаляем старое ограничение типов если оно есть
ALTER TABLE site_settings DROP CONSTRAINT IF EXISTS site_settings_setting_type_check;
-- Добавляем новое ограничение с расширенными типами
ALTER TABLE site_settings ADD CONSTRAINT site_settings_setting_type_check
CHECK (setting_type IN ('text', 'number', 'boolean', 'json', 'color', 'file'));
END $$;
-- Добавление расширенных настроек сайта для редактора стилей
INSERT INTO site_settings (setting_key, setting_value, setting_type, description, category, updated_at) VALUES
-- Основные цвета темы
('primary_color', '#2563eb', 'color', 'Основной цвет сайта', 'colors', NOW()),
('secondary_color', '#dc2626', 'color', 'Вторичный цвет сайта', 'colors', NOW()),
('accent_color', '#059669', 'color', 'Акцентный цвет', 'colors', NOW()),
('text_color', '#334155', 'color', 'Основной цвет текста', 'colors', NOW()),
('background_color', '#ffffff', 'color', 'Цвет фона', 'colors', NOW()),
('card_background', '#f8fafc', 'color', 'Цвет фона карточек', 'colors', NOW()),
-- Фоновые изображения
('hero_background_url', '/images/korea-hero.jpg', 'file', 'Фоновое изображение главной страницы', 'images', NOW()),
('default_tour_image', '/images/placeholder.jpg', 'file', 'Изображение тура по умолчанию', 'images', NOW()),
('site_logo_url', '/images/korea-logo.png', 'file', 'Логотип сайта', 'images', NOW()),
('favicon_url', '/images/favicon.ico', 'file', 'Иконка сайта', 'images', NOW()),
-- Типографика
('font_family_primary', 'Noto Sans KR, Malgun Gothic, 맑은 고딕, sans-serif', 'text', 'Основной шрифт', 'typography', NOW()),
('font_family_display', 'Playfair Display, serif', 'text', 'Декоративный шрифт', 'typography', NOW()),
('font_size_base', '16', 'number', 'Базовый размер шрифта (px)', 'typography', NOW()),
('line_height_base', '1.7', 'number', 'Базовая высота строки', 'typography', NOW()),
-- Эффекты и наложения
('hero_overlay_opacity', '0.8', 'number', 'Прозрачность наложения на hero фоне (0-1)', 'effects', NOW()),
('hero_overlay_color', '#2563eb', 'color', 'Цвет наложения на hero фоне', 'effects', NOW()),
('card_shadow', '0 4px 6px -1px rgba(0, 0, 0, 0.1)', 'text', 'Тень карточек (CSS shadow)', 'effects', NOW()),
('border_radius', '8', 'number', 'Радиус скругления углов (px)', 'effects', NOW()),
('blur_effect', '10', 'number', 'Сила размытия эффектов (px)', 'effects', NOW()),
-- Макет и размеры
('hero_height_desktop', '70', 'number', 'Высота hero секции на десктопе (vh)', 'layout', NOW()),
('hero_height_mobile', '50', 'number', 'Высота hero секции на мобильных (vh)', 'layout', NOW()),
('compact_hero_height', '25', 'number', 'Высота компактных hero секций (vh)', 'layout', NOW()),
('container_max_width', '1200', 'number', 'Максимальная ширина контейнера (px)', 'layout', NOW()),
('navbar_height', '76', 'number', 'Высота навигационной панели (px)', 'layout', NOW()),
-- Дополнительные стили
('custom_css', '', 'text', 'Дополнительный CSS код', 'theme', NOW()),
('google_fonts_url', '', 'text', 'URL для подключения Google Fonts', 'typography', NOW()),
('animation_duration', '0.3', 'number', 'Длительность анимаций (секунды)', 'effects', NOW())
ON CONFLICT (setting_key) DO UPDATE SET
setting_value = EXCLUDED.setting_value,
setting_type = EXCLUDED.setting_type,
description = EXCLUDED.description,
category = EXCLUDED.category,
updated_at = NOW();