diff --git a/backend/src/routes/adminSettings.js b/backend/src/routes/adminSettings.js index 624d2ac1..5a65cfb3 100644 --- a/backend/src/routes/adminSettings.js +++ b/backend/src/routes/adminSettings.js @@ -303,6 +303,16 @@ router.put('/branding', adminAuth, requirePermission('settings.edit'), async (re logo_display_mode, hide_powered_by, force_color_mode, + // Login-page-only branding (#354 follow-up). Both toggles apply + // exclusively to /admin/login and /customer/login — the gallery + // and admin chrome use their own logo_size / logo_max_height. + // - login_logo_frame_enabled: true (default) renders the tinted + // square behind the logo; false drops it. + // - login_logo_size: 'small' | 'medium' | 'large' | 'xlarge' + // matches the gallery logo_size token set but applies only to + // the two login screens. + login_logo_frame_enabled, + login_logo_size, // Footer overhaul (#441 + #440). Socials are URL strings (empty // hides the icon). Promo content is markdown (rendered via // marked → DOMPurify on the frontend, no raw HTML accepted). @@ -330,6 +340,13 @@ router.put('/branding', adminAuth, requirePermission('settings.edit'), async (re ? 'below_footer' : 'above_footer'; + // Normalize login_logo_size to the same token set as logo_size. + // Anything else falls back to 'medium' on the next render. + const allowedLoginLogoSizes = ['small', 'medium', 'large', 'xlarge']; + const normalizedLoginLogoSize = allowedLoginLogoSizes.includes(login_logo_size) + ? login_logo_size + : undefined; + const brandingSettings = { company_name, company_tagline, @@ -350,6 +367,11 @@ router.put('/branding', adminAuth, requirePermission('settings.edit'), async (re logo_display_mode, hide_powered_by, force_color_mode: normalizedForceColorMode, + // Login-only knobs (only persist when the request actually + // included the key, so a partial PUT from another tab doesn't + // accidentally clear them). + ...(login_logo_frame_enabled !== undefined && { login_logo_frame_enabled }), + ...(normalizedLoginLogoSize !== undefined && { login_logo_size: normalizedLoginLogoSize }), // Footer overhaul (#441 + #440). String fields normalize empty/ // undefined → '' so the column is always a known type. Only persist // when the request actually included the key (partial PUTs). diff --git a/backend/src/routes/publicSettings.js b/backend/src/routes/publicSettings.js index c468e2fe..3dce3721 100644 --- a/backend/src/routes/publicSettings.js +++ b/backend/src/routes/publicSettings.js @@ -85,6 +85,15 @@ router.get('/', async (req, res) => { : settingsObject.branding_force_color_mode === 'light' ? 'light' : null, + // Login-page-only branding (#354 follow-up). Applies exclusively + // to /admin/login and /customer/login — the rest of the app keeps + // using branding_logo_size / branding_logo_max_height. Default + // true / 'medium' preserves the visual state shipped before the + // toggles existed. + branding_login_logo_frame_enabled: settingsObject.branding_login_logo_frame_enabled !== false, + branding_login_logo_size: ['small', 'medium', 'large', 'xlarge'].includes(settingsObject.branding_login_logo_size) + ? settingsObject.branding_login_logo_size + : 'medium', theme_config: settingsObject.theme_config || null, default_language: settingsObject.general_default_language || 'en', enable_analytics: settingsObject.general_enable_analytics !== false, diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 74eec578..1f5ba37f 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -1771,6 +1771,17 @@ "straight": "Gerade", "angle": "Winkel", "curve": "Kurve" + }, + "loginLogo": { + "title": "Logo auf Login-Seiten", + "subtitle": "Wirkt nur auf /admin/login und /customer/login. Galerie und Admin-Chrome verwenden die Logo-Einstellungen oben.", + "frame": "Hellen Rahmen hinter dem Logo anzeigen", + "frameHelp": "Wenn aus, sitzt das Logo direkt auf dem Seitenhintergrund. Nützlich für Logos, die bereits einen eigenen Hintergrund haben.", + "size": "Logogröße auf den Login-Seiten", + "sizeSmall": "Klein", + "sizeMedium": "Mittel (Standard)", + "sizeLarge": "Groß", + "sizeXLarge": "Sehr groß" } }, "admin": { diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 2cfc2da2..b62c2ad0 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -1441,6 +1441,17 @@ "angle": "Angle", "curve": "Curve", "none": "None" + }, + "loginLogo": { + "title": "Login pages logo", + "subtitle": "Controls only /admin/login and /customer/login. Gallery and admin chrome use the logo settings above.", + "frame": "Show tinted frame behind the logo", + "frameHelp": "When off, the logo sits directly on the page background. Useful for logos that already include their own backdrop.", + "size": "Logo size on login pages", + "sizeSmall": "Small", + "sizeMedium": "Medium (default)", + "sizeLarge": "Large", + "sizeXLarge": "Extra large" } }, "admin": { diff --git a/frontend/src/i18n/locales/fr.json b/frontend/src/i18n/locales/fr.json index efff4521..2266670d 100644 --- a/frontend/src/i18n/locales/fr.json +++ b/frontend/src/i18n/locales/fr.json @@ -1379,6 +1379,17 @@ "straight": "Droit", "angle": "Angle", "curve": "Courbe" + }, + "loginLogo": { + "title": "Logo des pages de connexion", + "subtitle": "S'applique uniquement à /admin/login et /customer/login. La galerie et l'interface admin utilisent les paramètres de logo ci-dessus.", + "frame": "Afficher le cadre teinté derrière le logo", + "frameHelp": "Lorsque désactivé, le logo se pose directement sur l'arrière-plan de la page. Utile pour les logos qui ont déjà leur propre fond.", + "size": "Taille du logo sur les pages de connexion", + "sizeSmall": "Petite", + "sizeMedium": "Moyenne (par défaut)", + "sizeLarge": "Grande", + "sizeXLarge": "Très grande" } }, "admin": { diff --git a/frontend/src/i18n/locales/nl.json b/frontend/src/i18n/locales/nl.json index 7cdf19cd..edf6e28a 100644 --- a/frontend/src/i18n/locales/nl.json +++ b/frontend/src/i18n/locales/nl.json @@ -1441,6 +1441,17 @@ "straight": "Recht", "angle": "Hoek", "curve": "Boog" + }, + "loginLogo": { + "title": "Logo op loginpagina", + "subtitle": "Geldt alleen voor /admin/login en /customer/login. Galerij en beheer gebruiken de logo-instellingen hierboven.", + "frame": "Getint kader achter het logo tonen", + "frameHelp": "Wanneer uitgeschakeld staat het logo direct op de pagina-achtergrond. Handig voor logo's met een eigen achtergrond.", + "size": "Logogrootte op loginpagina's", + "sizeSmall": "Klein", + "sizeMedium": "Middel (standaard)", + "sizeLarge": "Groot", + "sizeXLarge": "Extra groot" } }, "admin": { diff --git a/frontend/src/i18n/locales/pt.json b/frontend/src/i18n/locales/pt.json index d2c23d79..538b5410 100644 --- a/frontend/src/i18n/locales/pt.json +++ b/frontend/src/i18n/locales/pt.json @@ -1458,6 +1458,17 @@ "straight": "Reto", "angle": "Ângulo", "curve": "Curva" + }, + "loginLogo": { + "title": "Logo nas páginas de login", + "subtitle": "Aplica-se apenas a /admin/login e /customer/login. A galeria e a interface admin usam as configurações de logo acima.", + "frame": "Mostrar moldura tonalizada atrás do logo", + "frameHelp": "Quando desativado, o logo fica diretamente sobre o fundo da página. Útil para logos que já incluem seu próprio fundo.", + "size": "Tamanho do logo nas páginas de login", + "sizeSmall": "Pequeno", + "sizeMedium": "Médio (padrão)", + "sizeLarge": "Grande", + "sizeXLarge": "Extra grande" } }, "admin": { diff --git a/frontend/src/i18n/locales/ru.json b/frontend/src/i18n/locales/ru.json index d9e5fb18..5a1dc993 100644 --- a/frontend/src/i18n/locales/ru.json +++ b/frontend/src/i18n/locales/ru.json @@ -1475,6 +1475,17 @@ "straight": "Прямой", "angle": "Угол", "curve": "Кривая" + }, + "loginLogo": { + "title": "Логотип на страницах входа", + "subtitle": "Применяется только к /admin/login и /customer/login. Галерея и админ-панель используют настройки логотипа выше.", + "frame": "Показывать тонированный фон за логотипом", + "frameHelp": "Если выключено, логотип будет на фоне страницы. Полезно для логотипов с собственным фоном.", + "size": "Размер логотипа на страницах входа", + "sizeSmall": "Маленький", + "sizeMedium": "Средний (по умолчанию)", + "sizeLarge": "Большой", + "sizeXLarge": "Очень большой" } }, "admin": { diff --git a/frontend/src/pages/admin/AdminLoginPage.tsx b/frontend/src/pages/admin/AdminLoginPage.tsx index 842584fc..d9ece291 100644 --- a/frontend/src/pages/admin/AdminLoginPage.tsx +++ b/frontend/src/pages/admin/AdminLoginPage.tsx @@ -8,6 +8,7 @@ import { Button, Input, Card, ReCaptcha } from '../../components/common'; import { useAdminAuth } from '../../contexts'; import { authService } from '../../services/auth.service'; import { usePublicSettings } from '../../hooks/usePublicSettings'; +import { resolveLoginLogoClasses } from '../../utils/loginLogoSize'; import { api } from '../../config/api'; export const AdminLoginPage: React.FC = () => { @@ -122,18 +123,32 @@ export const AdminLoginPage: React.FC = () => { return (
{t('adminLogin.subtitle')}
+ {t('branding.loginLogo.subtitle', 'Controls only /admin/login and /customer/login. Gallery and admin chrome use the logo settings above.')} +
+ +