From d59c1ad42a8393a92ebdeb140ec4d79b8d8b6514 Mon Sep 17 00:00:00 2001 From: "Andrey K. Choi" Date: Sun, 9 Nov 2025 13:00:25 +0900 Subject: [PATCH] Add color overlay settings for link buttons - Added link_overlay_enabled, link_overlay_color, link_overlay_opacity to DesignSettings model - Created migration 0008 for new fields - Updated CustomizationPanel with link overlay controls section - Added validation for new overlay settings in serializer - Updated PublicDesignSettingsSerializer to include overlay settings - Applied link overlay to all ExpandableGroup components in public page - Added preview in customization panel for link overlay effect --- DEPLOYMENT_INSTRUCTIONS.md | 57 +++++++++++ ...ignsettings_link_overlay_color_and_more.py | 28 ++++++ .../migrations/0009_merge_20251109_0356.py | 14 +++ backend/customization/models.py | 15 +++ backend/customization/serializers.py | 45 ++++++++- .../src/app/[username]/page.tsx | 18 +++- .../src/app/components/CustomizationPanel.tsx | 96 ++++++++++++++++++- 7 files changed, 267 insertions(+), 6 deletions(-) create mode 100644 DEPLOYMENT_INSTRUCTIONS.md create mode 100644 backend/customization/migrations/0008_designsettings_link_overlay_color_and_more.py create mode 100644 backend/customization/migrations/0009_merge_20251109_0356.py diff --git a/DEPLOYMENT_INSTRUCTIONS.md b/DEPLOYMENT_INSTRUCTIONS.md new file mode 100644 index 0000000..f7c46cb --- /dev/null +++ b/DEPLOYMENT_INSTRUCTIONS.md @@ -0,0 +1,57 @@ +# Инструкция по деплою исправлений скроллинга ссылок + +## Исправления внесены в следующие файлы: + +### 1. frontend/linktree-frontend/src/app/components/ExpandableGroup.tsx +- Исправлены стили компонента для корректного отображения как кнопки +- Добавлен класс `btn btn-outline-primary btn-sm` +- Изменены размеры иконок и текста +- Заменены h6 и p теги на span для корректного отображения в кнопке + +### 2. frontend/linktree-frontend/src/app/components/ExpandableGroup.module.css +- Обновлены размеры иконок с 40px на 20px +- Изменены отступы и стили для компактного отображения +- Добавлены стили для кнопочного представления +- Убран border и фон, чтобы использовать Bootstrap стили + +### 3. frontend/linktree-frontend/src/app/[username]/page.tsx +- Заменены все `group.links.slice(0, 5).map()` на `ExpandableGroup` +- Обновлены макеты: + - `renderGridLayout()` - использует ExpandableGroup + - `renderCardsLayout()` - использует ExpandableGroup + - `renderCompactLayout()` - использует ExpandableGroup + - `renderSidebarLayout()` - использует ExpandableGroup + - `renderMasonryLayout()` - уже использовал ExpandableGroup + - `renderMagazineLayout()` - уже использовал ExpandableGroup + - `renderTestListLayout()` - уже реализован + +## Команды для деплоя на сервере: + +```bash +# 1. Обновить код +cd /var/www/links +git pull origin master + +# 2. Пересобрать фронтенд +cd frontend/linktree-frontend +npm run build + +# 3. Перезапустить контейнеры +cd /var/www/links +docker-compose down +docker-compose up -d +``` + +## Результат: +Теперь во всех макетах групп ссылок: +- Отображается максимум 5-10 ссылок по умолчанию (зависит от макета) +- Есть кнопка "Показать еще X ссылок" если ссылок больше лимита +- Кнопка "Скрыть (X ссылок)" для сворачивания списка +- Иконки ссылок корректно отображаются во всех макетах +- Сохранены все стили дизайна + +## Исправленные проблемы: +✅ Скроллинг ссылок внутри группы +✅ Отображение иконок во всех макетах +✅ Единообразное поведение во всех layout'ах +✅ Адаптивность и красивый дизайн кнопок расширения \ No newline at end of file diff --git a/backend/customization/migrations/0008_designsettings_link_overlay_color_and_more.py b/backend/customization/migrations/0008_designsettings_link_overlay_color_and_more.py new file mode 100644 index 0000000..b1ea2d8 --- /dev/null +++ b/backend/customization/migrations/0008_designsettings_link_overlay_color_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.7 on 2025-11-09 14:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('customization', '0007_designsettings_body_font_family_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='designsettings', + name='link_overlay_color', + field=models.CharField(default='#000000', help_text='Цвет перекрытия кнопок ссылок (hex)', max_length=7), + ), + migrations.AddField( + model_name='designsettings', + name='link_overlay_enabled', + field=models.BooleanField(default=False, help_text='Включить цветовое перекрытие кнопок ссылок'), + ), + migrations.AddField( + model_name='designsettings', + name='link_overlay_opacity', + field=models.FloatField(default=0.2, help_text='Прозрачность перекрытия кнопок ссылок (0.0 - 1.0)'), + ), + ] \ No newline at end of file diff --git a/backend/customization/migrations/0009_merge_20251109_0356.py b/backend/customization/migrations/0009_merge_20251109_0356.py new file mode 100644 index 0000000..6ba3166 --- /dev/null +++ b/backend/customization/migrations/0009_merge_20251109_0356.py @@ -0,0 +1,14 @@ +# Generated by Django 5.2.7 on 2025-11-09 03:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('customization', '0008_add_template_id_and_test_list_layout'), + ('customization', '0008_designsettings_link_overlay_color_and_more'), + ] + + operations = [ + ] diff --git a/backend/customization/models.py b/backend/customization/models.py index 9e79a1d..de71d0b 100644 --- a/backend/customization/models.py +++ b/backend/customization/models.py @@ -149,6 +149,21 @@ class DesignSettings(models.Model): help_text='ID выбранного дизайн-шаблона' ) + # Новые поля для цветового оверлея кнопок ссылок + link_overlay_enabled = models.BooleanField( + default=False, + help_text='Включить цветовое перекрытие кнопок ссылок' + ) + link_overlay_color = models.CharField( + max_length=7, + default='#000000', + help_text='Цвет перекрытия кнопок ссылок (hex)' + ) + link_overlay_opacity = models.FloatField( + default=0.2, + help_text='Прозрачность перекрытия кнопок ссылок (0.0 - 1.0)' + ) + updated_at = models.DateTimeField( auto_now=True, help_text='Дата и время последнего изменения' diff --git a/backend/customization/serializers.py b/backend/customization/serializers.py index e7437a9..e95a88b 100644 --- a/backend/customization/serializers.py +++ b/backend/customization/serializers.py @@ -36,6 +36,9 @@ class DesignSettingsSerializer(serializers.ModelSerializer): 'group_description_text_color', 'body_font_family', 'heading_font_family', + 'link_overlay_enabled', + 'link_overlay_color', + 'link_overlay_opacity', 'updated_at' ] read_only_fields = ['id', 'updated_at', 'background_image_url'] @@ -261,6 +264,26 @@ class DesignSettingsSerializer(serializers.ModelSerializer): raise serializers.ValidationError('ID шаблона слишком длинный') return value + def validate_link_overlay_color(self, value): + """ + Валидация цвета перекрытия кнопок ссылок + """ + if not value.startswith('#') or len(value) != 7: + raise serializers.ValidationError('Цвет должен быть в формате #RRGGBB') + try: + int(value[1:], 16) + except ValueError: + raise serializers.ValidationError('Некорректный hex цвет') + return value + + def validate_link_overlay_opacity(self, value): + """ + Валидация прозрачности перекрытия кнопок ссылок + """ + if not 0.0 <= value <= 1.0: + raise serializers.ValidationError('Прозрачность должна быть между 0.0 и 1.0') + return value + class PublicDesignSettingsSerializer(serializers.ModelSerializer): """ @@ -273,8 +296,28 @@ class PublicDesignSettingsSerializer(serializers.ModelSerializer): fields = [ 'theme_color', 'background_image_url', + 'dashboard_layout', + 'groups_default_expanded', + 'show_group_icons', + 'show_link_icons', + 'dashboard_background_color', 'font_family', - 'custom_css' + 'header_text_color', + 'group_text_color', + 'link_text_color', + 'group_overlay_enabled', + 'group_overlay_color', + 'group_overlay_opacity', + 'show_groups_title', + 'group_description_text_color', + 'body_font_family', + 'heading_font_family', + 'cover_overlay_enabled', + 'cover_overlay_color', + 'cover_overlay_opacity', + 'link_overlay_enabled', + 'link_overlay_color', + 'link_overlay_opacity' ] def get_background_image_url(self, obj): diff --git a/frontend/linktree-frontend/src/app/[username]/page.tsx b/frontend/linktree-frontend/src/app/[username]/page.tsx index bce0329..d70717d 100644 --- a/frontend/linktree-frontend/src/app/[username]/page.tsx +++ b/frontend/linktree-frontend/src/app/[username]/page.tsx @@ -62,6 +62,10 @@ interface PublicDesignSettings { cover_overlay_enabled?: boolean cover_overlay_color?: string cover_overlay_opacity?: number + // Новые поля для цветового оверлея кнопок ссылок + link_overlay_enabled?: boolean + link_overlay_color?: string + link_overlay_opacity?: number } export default function UserPage({ @@ -315,6 +319,8 @@ export default function UserPage({ initialShowCount={5} className="" linkClassName="btn btn-outline-primary btn-sm d-flex align-items-center justify-content-start" + overlayColor={designSettings.link_overlay_enabled ? designSettings.link_overlay_color : undefined} + overlayOpacity={designSettings.link_overlay_enabled ? designSettings.link_overlay_opacity : undefined} /> @@ -474,6 +480,8 @@ export default function UserPage({ initialShowCount={10} className="row" linkClassName="col-auto mb-1" + overlayColor={designSettings.link_overlay_enabled ? designSettings.link_overlay_color : undefined} + overlayOpacity={designSettings.link_overlay_enabled ? designSettings.link_overlay_opacity : undefined} /> @@ -554,6 +562,8 @@ export default function UserPage({ initialShowCount={6} className="row" linkClassName="col-12 col-md-6 col-lg-4 mb-3" + overlayColor={designSettings.link_overlay_enabled ? designSettings.link_overlay_color : undefined} + overlayOpacity={designSettings.link_overlay_enabled ? designSettings.link_overlay_opacity : undefined} /> @@ -687,8 +697,8 @@ export default function UserPage({ links={group.links} layout="timeline" initialShowCount={5} - overlayColor={designSettings.group_overlay_enabled ? designSettings.group_overlay_color : undefined} - overlayOpacity={designSettings.group_overlay_enabled ? designSettings.group_overlay_opacity : undefined} + overlayColor={designSettings.link_overlay_enabled ? designSettings.link_overlay_color : undefined} + overlayOpacity={designSettings.link_overlay_enabled ? designSettings.link_overlay_opacity : undefined} /> @@ -773,8 +783,8 @@ export default function UserPage({ links={group.links} layout="magazine" initialShowCount={index === 0 ? 5 : 3} - overlayColor={designSettings.group_overlay_enabled ? designSettings.group_overlay_color : undefined} - overlayOpacity={designSettings.group_overlay_enabled ? designSettings.group_overlay_opacity : undefined} + overlayColor={designSettings.link_overlay_enabled ? designSettings.link_overlay_color : undefined} + overlayOpacity={designSettings.link_overlay_enabled ? designSettings.link_overlay_opacity : undefined} /> diff --git a/frontend/linktree-frontend/src/app/components/CustomizationPanel.tsx b/frontend/linktree-frontend/src/app/components/CustomizationPanel.tsx index f591d19..75ddf00 100644 --- a/frontend/linktree-frontend/src/app/components/CustomizationPanel.tsx +++ b/frontend/linktree-frontend/src/app/components/CustomizationPanel.tsx @@ -31,6 +31,10 @@ interface DesignSettings { group_description_text_color?: string body_font_family?: string heading_font_family?: string + // Новые поля для цветового оверлея кнопок ссылок + link_overlay_enabled?: boolean + link_overlay_color?: string + link_overlay_opacity?: number } interface CustomizationPanelProps { @@ -115,6 +119,9 @@ export function CustomizationPanel({ isOpen, onClose, onSettingsUpdate }: Custom formData.append('group_description_text_color', settings.group_description_text_color || '#666666') formData.append('body_font_family', settings.body_font_family || 'sans-serif') formData.append('heading_font_family', settings.heading_font_family || 'sans-serif') + formData.append('link_overlay_enabled', (settings.link_overlay_enabled || false).toString()) + formData.append('link_overlay_color', settings.link_overlay_color || '#000000') + formData.append('link_overlay_opacity', (settings.link_overlay_opacity || 0.2).toString()) formData.append('background_image', backgroundImageFile) const response = await fetch(`${API}/api/customization/settings/`, { @@ -158,7 +165,10 @@ export function CustomizationPanel({ isOpen, onClose, onSettingsUpdate }: Custom show_groups_title: settings.show_groups_title !== false, group_description_text_color: settings.group_description_text_color || '#666666', body_font_family: settings.body_font_family || 'sans-serif', - heading_font_family: settings.heading_font_family || 'sans-serif' + heading_font_family: settings.heading_font_family || 'sans-serif', + link_overlay_enabled: settings.link_overlay_enabled || false, + link_overlay_color: settings.link_overlay_color || '#000000', + link_overlay_opacity: settings.link_overlay_opacity || 0.2 } const response = await fetch(`${API}/api/customization/settings/`, { @@ -703,6 +713,90 @@ export function CustomizationPanel({ isOpen, onClose, onSettingsUpdate }: Custom Чтобы настроить конкретную группу (публичность, избранное, разворачивание), используйте кнопку редактирования рядом с названием группы в основном списке. + + {/* Секция цветового оверлея кнопок ссылок */} +
+
+
+
Цветовое перекрытие кнопок ссылок
+
+ { + console.log('Link overlay enabled:', e.target.checked) + handleChange('link_overlay_enabled', e.target.checked) + }} + /> + +
+
+ +
+ {settings.link_overlay_enabled && ( + <> +
+ + { + console.log('Link overlay color:', e.target.value) + handleChange('link_overlay_color', e.target.value) + }} + /> +
+
+ + { + const value = parseFloat(e.target.value) + console.log('Link overlay opacity:', value) + handleChange('link_overlay_opacity', value) + }} + /> +
+
+ +
+
+ Кнопка ссылки +
+
+
+
+ + )} +
+
+
)}