Fix mobile responsiveness and implement enhanced theme system

- Fixed mobile gallery login box sizing and layout
- Fixed header button layout for mobile screens
- Fixed duplicate logo issue on logout
- Fixed '0' rendering when upload button is hidden
- Fixed horizontal scrolling on small screens

- Implemented comprehensive theme system with gallery layouts
- Added 6 different gallery layouts: Grid, Masonry, Carousel, Timeline, Hero, Mosaic
- Created enhanced theme customizer with layout selection
- Added theme presets for different event types
- Updated event creation with theme preview and customization
- Fixed all TypeScript compilation errors

- Added missing translation keys for create event page
- Added translations for theme customization features

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-09 11:26:27 +02:00
parent d8fb4c9565
commit 6438374258
23 changed files with 2798 additions and 168 deletions
@@ -51,74 +51,90 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
{/* Header */}
<header className="bg-white border-b border-neutral-200 sticky top-0 z-40">
<div className="container py-3 sm:py-4">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
<div className="flex items-start sm:items-center gap-3 sm:gap-4">
{/* Company logo */}
{brandingSettings?.logo_url && (
<div className="hidden sm:block pr-4 border-r border-neutral-200 flex-shrink-0">
<img
src={`${import.meta.env.VITE_API_URL || 'http://localhost:3001'}${brandingSettings.logo_url}`}
alt={brandingSettings.company_name || 'Company Logo'}
className="h-10 sm:h-12 w-auto object-contain"
/>
</div>
)}
{/* Company branding */}
{!brandingSettings?.logo_url && brandingSettings?.company_name && (
<div className="hidden sm:block pr-4 border-r border-neutral-200 flex-shrink-0">
<h2 className="text-base sm:text-lg font-semibold text-neutral-800">{brandingSettings.company_name}</h2>
{brandingSettings.company_tagline && (
<p className="hidden lg:block text-xs text-neutral-600">{brandingSettings.company_tagline}</p>
)}
</div>
)}
<div className="flex-1">
<h1 className="text-xl sm:text-2xl font-bold text-neutral-900 leading-tight">{event.event_name}</h1>
{(event.event_date || event.expires_at) && (
<div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-4 mt-1 text-xs sm:text-sm text-neutral-600">
{event.event_date && (
<span className="flex items-center">
<Calendar className="w-3 h-3 sm:w-4 sm:h-4 mr-1" />
<span className="truncate">{format(parseISO(event.event_date), 'PP')}</span>
</span>
)}
{event.expires_at && (
<span className="flex items-center">
<Clock className="w-3 h-3 sm:w-4 sm:h-4 mr-1" />
<span className="truncate">{t('gallery.expires')} {format(parseISO(event.expires_at), 'PP')}</span>
</span>
)}
<div className="container py-3">
<div className="flex flex-col gap-3">
{/* Top row - Title and mobile logout */}
<div className="flex items-start justify-between gap-3">
<div className="flex items-start gap-3 flex-1 min-w-0">
{/* Logo - Mobile optimized */}
{brandingSettings?.logo_url && (
<div className="flex-shrink-0">
<img
src={`${import.meta.env.VITE_API_URL || 'http://localhost:3001'}${brandingSettings.logo_url}`}
alt={brandingSettings.company_name || 'Company Logo'}
className="h-8 sm:h-10 lg:h-12 w-auto object-contain"
/>
</div>
)}
{/* Event info */}
<div className="flex-1 min-w-0">
<h1 className="text-lg sm:text-xl lg:text-2xl font-bold text-neutral-900 leading-tight truncate">
{event.event_name}
</h1>
{(event.event_date || event.expires_at) && (
<div className="flex flex-wrap gap-x-3 gap-y-1 mt-1 text-xs text-neutral-600">
{event.event_date && (
<span className="flex items-center">
<Calendar className="w-3 h-3 mr-1 flex-shrink-0" />
<span>{format(parseISO(event.event_date), 'PP')}</span>
</span>
)}
{event.expires_at && (
<span className="flex items-center">
<Clock className="w-3 h-3 mr-1 flex-shrink-0" />
<span>{t('gallery.expires')} {format(parseISO(event.expires_at), 'PP')}</span>
</span>
)}
</div>
)}
</div>
</div>
{/* Mobile logout button - top right */}
{showLogout && onLogout && (
<Button
variant="ghost"
size="sm"
onClick={onLogout}
className="sm:hidden p-2"
title={t('common.logout')}
>
<LogOut className="w-5 h-5" />
</Button>
)}
</div>
<div className="flex items-center gap-2 flex-wrap sm:flex-nowrap">
{headerExtra}
{/* Action buttons row */}
<div className="flex items-center gap-2">
{/* Header extra content (upload button, countdown) */}
{headerExtra && headerExtra}
{/* Download all button */}
{showDownloadAll && onDownloadAll && (
<Button
variant="primary"
size="md"
size="sm"
leftIcon={<Download className="w-4 h-4" />}
onClick={onDownloadAll}
isLoading={isDownloading}
className="flex-1 sm:flex-initial text-sm sm:text-base"
className="flex-1 sm:flex-initial"
>
<span className="hidden sm:inline">{t('gallery.downloadAll')}</span>
<span className="sm:hidden">{t('common.downloadAll')}</span>
<span className="sm:hidden">{t('common.download')}</span>
</Button>
)}
{/* Desktop logout button */}
{showLogout && onLogout && (
<Button
variant="outline"
size="md"
size="sm"
leftIcon={<LogOut className="w-4 h-4" />}
onClick={onLogout}
className="text-sm sm:text-base"
className="hidden sm:flex"
>
<span className="hidden sm:inline">{t('common.logout')}</span>
<span className="sm:hidden"><LogOut className="w-4 h-4" /></span>
{t('common.logout')}
</Button>
)}
</div>