feat: implement gallery logo customization (Issue #17)
Added comprehensive logo customization features for gallery views: - Logo size options (small, medium, large, xlarge, custom) - Logo position control (left, center, right) - Display mode settings (logo only, text only, logo and text) - Visibility controls for header and hero sections - Custom height configuration for fine-tuning Changes: - Added database migration for 6 new logo customization settings - Extended backend APIs to handle logo customization fields - Updated GalleryLayout.tsx with dynamic logo rendering logic - Added logo upload functionality to BrandingPage.tsx - Extended settings service with logo customization types This addresses the issue where the gallery logo was "very large and centered" by providing full control over logo appearance and positioning. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
exports.up = async function(knex) {
|
||||
console.log('Running migration: 041_add_logo_customization_settings');
|
||||
|
||||
// Add default logo customization settings
|
||||
const logoSettings = [
|
||||
{
|
||||
setting_key: 'branding_logo_size',
|
||||
setting_value: JSON.stringify('medium'),
|
||||
setting_type: 'branding',
|
||||
description: 'Logo size: small, medium, large, xlarge, or custom',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
},
|
||||
{
|
||||
setting_key: 'branding_logo_max_height',
|
||||
setting_value: JSON.stringify(48),
|
||||
setting_type: 'branding',
|
||||
description: 'Maximum logo height in pixels (used when size is custom)',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
},
|
||||
{
|
||||
setting_key: 'branding_logo_position',
|
||||
setting_value: JSON.stringify('left'),
|
||||
setting_type: 'branding',
|
||||
description: 'Logo position in header: left, center, right',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
},
|
||||
{
|
||||
setting_key: 'branding_logo_display_header',
|
||||
setting_value: JSON.stringify(true),
|
||||
setting_type: 'branding',
|
||||
description: 'Show logo in gallery header',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
},
|
||||
{
|
||||
setting_key: 'branding_logo_display_hero',
|
||||
setting_value: JSON.stringify(true),
|
||||
setting_type: 'branding',
|
||||
description: 'Show logo in hero section (for non-grid layouts)',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
},
|
||||
{
|
||||
setting_key: 'branding_logo_display_mode',
|
||||
setting_value: JSON.stringify('logo_and_text'),
|
||||
setting_type: 'branding',
|
||||
description: 'Display mode: logo_only, text_only, logo_and_text',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
}
|
||||
];
|
||||
|
||||
// Insert settings that don't already exist
|
||||
for (const setting of logoSettings) {
|
||||
const exists = await knex('app_settings')
|
||||
.where('setting_key', setting.setting_key)
|
||||
.first();
|
||||
|
||||
if (!exists) {
|
||||
await knex('app_settings').insert(setting);
|
||||
console.log(`Added setting: ${setting.setting_key}`);
|
||||
} else {
|
||||
console.log(`Setting already exists: ${setting.setting_key}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Migration 041_add_logo_customization_settings completed');
|
||||
};
|
||||
|
||||
exports.down = async function(knex) {
|
||||
console.log('Rolling back migration: 041_add_logo_customization_settings');
|
||||
|
||||
// Remove the logo customization settings
|
||||
await knex('app_settings')
|
||||
.whereIn('setting_key', [
|
||||
'branding_logo_size',
|
||||
'branding_logo_max_height',
|
||||
'branding_logo_position',
|
||||
'branding_logo_display_header',
|
||||
'branding_logo_display_hero',
|
||||
'branding_logo_display_mode'
|
||||
])
|
||||
.del();
|
||||
|
||||
console.log('Rollback of 041_add_logo_customization_settings completed');
|
||||
};
|
||||
@@ -170,7 +170,13 @@ router.put('/branding', adminAuth, async (req, res) => {
|
||||
watermark_size,
|
||||
favicon_url,
|
||||
logo_url,
|
||||
watermark_logo_url
|
||||
watermark_logo_url,
|
||||
logo_size,
|
||||
logo_max_height,
|
||||
logo_position,
|
||||
logo_display_header,
|
||||
logo_display_hero,
|
||||
logo_display_mode
|
||||
} = req.body;
|
||||
|
||||
const brandingSettings = {
|
||||
@@ -184,7 +190,13 @@ router.put('/branding', adminAuth, async (req, res) => {
|
||||
watermark_size,
|
||||
favicon_url,
|
||||
logo_url,
|
||||
watermark_logo_url
|
||||
watermark_logo_url,
|
||||
logo_size,
|
||||
logo_max_height,
|
||||
logo_position,
|
||||
logo_display_header,
|
||||
logo_display_hero,
|
||||
logo_display_mode
|
||||
};
|
||||
|
||||
// Handle favicon deletion if empty string or null is provided
|
||||
|
||||
@@ -42,6 +42,12 @@ router.get('/', async (req, res) => {
|
||||
branding_watermark_size: settingsObject.branding_watermark_size || 15,
|
||||
branding_favicon_url: settingsObject.branding_favicon_url || '',
|
||||
branding_logo_url: settingsObject.branding_logo_url || '',
|
||||
branding_logo_size: settingsObject.branding_logo_size || 'medium',
|
||||
branding_logo_max_height: settingsObject.branding_logo_max_height || 48,
|
||||
branding_logo_position: settingsObject.branding_logo_position || 'left',
|
||||
branding_logo_display_header: settingsObject.branding_logo_display_header !== false,
|
||||
branding_logo_display_hero: settingsObject.branding_logo_display_hero !== false,
|
||||
branding_logo_display_mode: settingsObject.branding_logo_display_mode || 'logo_and_text',
|
||||
theme_config: settingsObject.theme_config || null,
|
||||
default_language: settingsObject.general_default_language || 'en',
|
||||
enable_analytics: settingsObject.general_enable_analytics !== false,
|
||||
|
||||
@@ -23,6 +23,12 @@ interface GalleryLayoutProps {
|
||||
footer_text?: string;
|
||||
favicon_url?: string;
|
||||
logo_url?: string;
|
||||
logo_size?: 'small' | 'medium' | 'large' | 'xlarge' | 'custom';
|
||||
logo_max_height?: number;
|
||||
logo_position?: 'left' | 'center' | 'right';
|
||||
logo_display_header?: boolean;
|
||||
logo_display_hero?: boolean;
|
||||
logo_display_mode?: 'logo_only' | 'text_only' | 'logo_and_text';
|
||||
};
|
||||
showLogout?: boolean;
|
||||
onLogout?: () => void;
|
||||
@@ -56,6 +62,53 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
|
||||
const fontFamily = theme.fontFamily || 'Inter, sans-serif';
|
||||
const headingFontFamily = theme.headingFontFamily || fontFamily;
|
||||
|
||||
// Calculate logo size classes based on settings
|
||||
const getLogoSizeClass = (context: 'header' | 'hero') => {
|
||||
const size = brandingSettings?.logo_size || 'medium';
|
||||
const maxHeight = brandingSettings?.logo_max_height || 48;
|
||||
|
||||
if (size === 'custom') {
|
||||
return { maxHeight: `${maxHeight}px`, height: 'auto' };
|
||||
}
|
||||
|
||||
const sizeMap = {
|
||||
small: context === 'header' ? 'h-6 sm:h-8' : 'h-12 sm:h-14 lg:h-16',
|
||||
medium: context === 'header' ? 'h-8 sm:h-10 lg:h-12' : 'h-16 sm:h-20 lg:h-24',
|
||||
large: context === 'header' ? 'h-10 sm:h-12 lg:h-16' : 'h-20 sm:h-24 lg:h-32',
|
||||
xlarge: context === 'header' ? 'h-12 sm:h-16 lg:h-20' : 'h-24 sm:h-32 lg:h-40'
|
||||
};
|
||||
|
||||
return sizeMap[size] || sizeMap.medium;
|
||||
};
|
||||
|
||||
// Determine logo position classes
|
||||
const getLogoPositionClass = () => {
|
||||
const position = brandingSettings?.logo_position || 'left';
|
||||
return {
|
||||
left: 'justify-start',
|
||||
center: 'justify-center',
|
||||
right: 'justify-end'
|
||||
}[position];
|
||||
};
|
||||
|
||||
// Check if logo should be displayed
|
||||
const shouldShowLogo = (context: 'header' | 'hero') => {
|
||||
const displayMode = brandingSettings?.logo_display_mode || 'logo_and_text';
|
||||
if (displayMode === 'text_only') return false;
|
||||
|
||||
if (context === 'header') {
|
||||
return brandingSettings?.logo_display_header !== false;
|
||||
} else {
|
||||
return brandingSettings?.logo_display_hero !== false;
|
||||
}
|
||||
};
|
||||
|
||||
// Check if company name should be displayed
|
||||
const shouldShowCompanyName = () => {
|
||||
const displayMode = brandingSettings?.logo_display_mode || 'logo_and_text';
|
||||
return displayMode !== 'logo_only';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-neutral-50">
|
||||
{/* Dynamic Favicon */}
|
||||
@@ -122,16 +175,31 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
|
||||
)}
|
||||
|
||||
{/* Logo - Show custom logo or fallback to PicPeak logo */}
|
||||
<div className="flex-shrink-0">
|
||||
<img
|
||||
src={brandingSettings?.logo_url ?
|
||||
buildResourceUrl(brandingSettings.logo_url) :
|
||||
'/picpeak-logo-transparent.png'
|
||||
}
|
||||
alt={brandingSettings?.company_name || 'PicPeak'}
|
||||
className="h-8 sm:h-10 lg:h-12 w-auto object-contain"
|
||||
/>
|
||||
</div>
|
||||
{shouldShowLogo('header') && (
|
||||
<div className={`flex-shrink-0 flex items-center gap-2 ${brandingSettings?.logo_position === 'center' ? 'flex-1' : ''} ${getLogoPositionClass()}`}>
|
||||
<img
|
||||
src={brandingSettings?.logo_url ?
|
||||
buildResourceUrl(brandingSettings.logo_url) :
|
||||
'/picpeak-logo-transparent.png'
|
||||
}
|
||||
alt={brandingSettings?.company_name || 'PicPeak'}
|
||||
className={`${typeof getLogoSizeClass('header') === 'string' ? getLogoSizeClass('header') : ''} w-auto object-contain`}
|
||||
style={typeof getLogoSizeClass('header') === 'object' ? getLogoSizeClass('header') : undefined}
|
||||
/>
|
||||
{shouldShowCompanyName() && brandingSettings?.company_name && (
|
||||
<span className="hidden sm:inline text-lg font-semibold text-neutral-900">
|
||||
{brandingSettings.company_name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!shouldShowLogo('header') && shouldShowCompanyName() && brandingSettings?.company_name && (
|
||||
<div className={`flex-shrink-0 ${brandingSettings?.logo_position === 'center' ? 'flex-1' : ''} ${getLogoPositionClass()}`}>
|
||||
<span className="text-lg font-semibold text-neutral-900">
|
||||
{brandingSettings.company_name || 'PicPeak'}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Center - Event info */}
|
||||
@@ -277,19 +345,32 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
|
||||
<div className="container py-12 sm:py-16 lg:py-20 relative z-10">
|
||||
<div className="text-center max-w-4xl mx-auto">
|
||||
{/* Logo - Show custom logo or fallback to PicPeak logo */}
|
||||
<div className="mb-6">
|
||||
<img
|
||||
src={brandingSettings?.logo_url ?
|
||||
buildResourceUrl(brandingSettings.logo_url) :
|
||||
'/picpeak-logo-transparent.png'
|
||||
}
|
||||
alt={brandingSettings?.company_name || 'PicPeak'}
|
||||
className="h-16 sm:h-20 lg:h-24 w-auto object-contain mx-auto"
|
||||
style={{
|
||||
filter: 'brightness(0) invert(1) drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3))'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{shouldShowLogo('hero') && (
|
||||
<div className="mb-6">
|
||||
<img
|
||||
src={brandingSettings?.logo_url ?
|
||||
buildResourceUrl(brandingSettings.logo_url) :
|
||||
'/picpeak-logo-transparent.png'
|
||||
}
|
||||
alt={brandingSettings?.company_name || 'PicPeak'}
|
||||
className={`${typeof getLogoSizeClass('hero') === 'string' ? getLogoSizeClass('hero') : ''} w-auto object-contain mx-auto`}
|
||||
style={typeof getLogoSizeClass('hero') === 'object' ?
|
||||
{ ...getLogoSizeClass('hero'), filter: 'brightness(0) invert(1) drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3))' } :
|
||||
{ filter: 'brightness(0) invert(1) drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3))' }
|
||||
}
|
||||
/>
|
||||
{shouldShowCompanyName() && brandingSettings?.company_name && (
|
||||
<div className="mt-3 text-xl sm:text-2xl font-semibold text-white/90" style={{ textShadow: '0 2px 4px rgba(0, 0, 0, 0.3)' }}>
|
||||
{brandingSettings.company_name}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!shouldShowLogo('hero') && shouldShowCompanyName() && brandingSettings?.company_name && (
|
||||
<div className="mb-6 text-2xl sm:text-3xl font-bold text-white" style={{ textShadow: '0 2px 4px rgba(0, 0, 0, 0.3)' }}>
|
||||
{brandingSettings.company_name || 'PicPeak'}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Event Name */}
|
||||
<h1
|
||||
|
||||
@@ -144,6 +144,21 @@ export const BrandingPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleLogoUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
try {
|
||||
const logoUrl = await settingsService.uploadLogo(file);
|
||||
setBrandingSettings(prev => ({ ...prev, logo_url: logoUrl }));
|
||||
setCurrentTheme(prev => ({ ...prev, logoUrl }));
|
||||
toast.success(t('toast.uploadSuccess'));
|
||||
} catch (error) {
|
||||
console.error('Failed to upload logo:', error);
|
||||
toast.error(t('toast.uploadError'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleWatermarkLogoUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
@@ -316,6 +331,166 @@ export const BrandingPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Logo Customization Settings */}
|
||||
<div className="mt-6 pt-6 border-t border-neutral-200">
|
||||
<h3 className="text-md font-semibold text-neutral-900 mb-4">{t('branding.logoCustomization', 'Logo Customization')}</h3>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* Logo Upload */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-neutral-700 mb-2">
|
||||
{t('branding.logo', 'Logo')}
|
||||
</label>
|
||||
<div className="flex items-center gap-4">
|
||||
{brandingSettings.logo_url && (
|
||||
<div className="relative">
|
||||
<img
|
||||
src={brandingSettings.logo_url.startsWith('http') ? brandingSettings.logo_url : buildResourceUrl(brandingSettings.logo_url)}
|
||||
alt="Logo"
|
||||
className="h-16 object-contain bg-neutral-100 rounded p-2"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleBrandingChange('logo_url', '')}
|
||||
className="absolute -top-2 -right-2 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center hover:bg-red-600"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<label className="cursor-pointer">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/png,image/jpeg,image/svg+xml"
|
||||
onChange={handleLogoUpload}
|
||||
className="hidden"
|
||||
/>
|
||||
<span className="btn-secondary inline-flex items-center">
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
{brandingSettings.logo_url ? t('branding.changeLogo', 'Change Logo') : t('branding.uploadLogo', 'Upload Logo')}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<p className="text-xs text-neutral-600 mt-1">
|
||||
{t('branding.logoHelp', 'PNG, JPG or SVG format, recommended width: 200px')}
|
||||
</p>
|
||||
</div>
|
||||
{/* Logo Size */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-neutral-700 mb-2">
|
||||
{t('branding.logoSize', 'Logo Size')}
|
||||
</label>
|
||||
<select
|
||||
value={brandingSettings.logo_size || 'medium'}
|
||||
onChange={(e) => handleBrandingChange('logo_size', e.target.value)}
|
||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg focus:ring-2 focus:ring-primary-500"
|
||||
>
|
||||
<option value="small">{t('branding.logoSizeSmall', 'Small (32px)')}</option>
|
||||
<option value="medium">{t('branding.logoSizeMedium', 'Medium (48px)')}</option>
|
||||
<option value="large">{t('branding.logoSizeLarge', 'Large (64px)')}</option>
|
||||
<option value="xlarge">{t('branding.logoSizeXLarge', 'Extra Large (96px)')}</option>
|
||||
<option value="custom">{t('branding.logoSizeCustom', 'Custom')}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Custom Height (only shown when size is custom) */}
|
||||
{brandingSettings.logo_size === 'custom' && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-neutral-700 mb-2">
|
||||
{t('branding.logoMaxHeight', 'Maximum Height (pixels)')}
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="20"
|
||||
max="200"
|
||||
value={brandingSettings.logo_max_height || 48}
|
||||
onChange={(e) => handleBrandingChange('logo_max_height', parseInt(e.target.value))}
|
||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg focus:ring-2 focus:ring-primary-500"
|
||||
/>
|
||||
<p className="text-xs text-neutral-600 mt-1">
|
||||
{t('branding.logoMaxHeightHelp', 'Set a custom maximum height for the logo (20-200 pixels)')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Logo Position */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-neutral-700 mb-2">
|
||||
{t('branding.logoPosition', 'Logo Position in Header')}
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
{(['left', 'center', 'right'] as const).map((position) => (
|
||||
<button
|
||||
key={position}
|
||||
type="button"
|
||||
onClick={() => handleBrandingChange('logo_position', position)}
|
||||
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
||||
brandingSettings.logo_position === position
|
||||
? 'bg-primary-600 text-white'
|
||||
: 'bg-neutral-100 text-neutral-700 hover:bg-neutral-200'
|
||||
}`}
|
||||
>
|
||||
{t(`branding.position${position.charAt(0).toUpperCase() + position.slice(1)}`, position.charAt(0).toUpperCase() + position.slice(1))}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Display Mode */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-neutral-700 mb-2">
|
||||
{t('branding.logoDisplayMode', 'Display Mode')}
|
||||
</label>
|
||||
<select
|
||||
value={brandingSettings.logo_display_mode || 'logo_and_text'}
|
||||
onChange={(e) => handleBrandingChange('logo_display_mode', e.target.value)}
|
||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg focus:ring-2 focus:ring-primary-500"
|
||||
>
|
||||
<option value="logo_only">{t('branding.logoOnly', 'Logo Only')}</option>
|
||||
<option value="text_only">{t('branding.textOnly', 'Company Name Only')}</option>
|
||||
<option value="logo_and_text">{t('branding.logoAndText', 'Logo and Company Name')}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Display Options */}
|
||||
<div className="space-y-3">
|
||||
<label className="flex items-center gap-3 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={brandingSettings.logo_display_header !== false}
|
||||
onChange={(e) => handleBrandingChange('logo_display_header', e.target.checked)}
|
||||
className="rounded border-neutral-300 text-primary-600 focus:ring-primary-500"
|
||||
/>
|
||||
<div>
|
||||
<span className="text-sm font-medium text-neutral-900">
|
||||
{t('branding.showLogoInHeader', 'Show logo in gallery header')}
|
||||
</span>
|
||||
<p className="text-xs text-neutral-600">
|
||||
{t('branding.showLogoInHeaderHelp', 'Display the logo in the main header bar')}
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-3 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={brandingSettings.logo_display_hero !== false}
|
||||
onChange={(e) => handleBrandingChange('logo_display_hero', e.target.checked)}
|
||||
className="rounded border-neutral-300 text-primary-600 focus:ring-primary-500"
|
||||
/>
|
||||
<div>
|
||||
<span className="text-sm font-medium text-neutral-900">
|
||||
{t('branding.showLogoInHero', 'Show logo in hero section')}
|
||||
</span>
|
||||
<p className="text-xs text-neutral-600">
|
||||
{t('branding.showLogoInHeroHelp', 'Display the logo in hero sections (for non-grid layouts)')}
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 pt-6 border-t border-neutral-200">
|
||||
<label className="flex items-center gap-3 cursor-pointer">
|
||||
<input
|
||||
|
||||
@@ -12,6 +12,12 @@ export interface BrandingSettings {
|
||||
watermark_logo_url?: string;
|
||||
logo_url?: string;
|
||||
favicon_url?: string;
|
||||
logo_size?: 'small' | 'medium' | 'large' | 'xlarge' | 'custom';
|
||||
logo_max_height?: number;
|
||||
logo_position?: 'left' | 'center' | 'right';
|
||||
logo_display_header?: boolean;
|
||||
logo_display_hero?: boolean;
|
||||
logo_display_mode?: 'logo_only' | 'text_only' | 'logo_and_text';
|
||||
}
|
||||
|
||||
export interface ThemeSettings {
|
||||
@@ -215,7 +221,13 @@ export const settingsService = {
|
||||
watermark_size: rawSettings.branding_watermark_size || 15,
|
||||
watermark_logo_url: rawSettings.branding_watermark_logo_url || undefined,
|
||||
logo_url: rawSettings.branding_logo_url || undefined,
|
||||
favicon_url: rawSettings.branding_favicon_url || undefined
|
||||
favicon_url: rawSettings.branding_favicon_url || undefined,
|
||||
logo_size: rawSettings.branding_logo_size || 'medium',
|
||||
logo_max_height: rawSettings.branding_logo_max_height || 48,
|
||||
logo_position: rawSettings.branding_logo_position || 'left',
|
||||
logo_display_header: rawSettings.branding_logo_display_header !== false,
|
||||
logo_display_hero: rawSettings.branding_logo_display_hero !== false,
|
||||
logo_display_mode: rawSettings.branding_logo_display_mode || 'logo_and_text'
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user