fix: render minimal/none header styles, cap hero height, switch category hero images (#158, #162, #163)

- Add distinct rendering branches for minimal and none header styles in
  GalleryLayout (grid and non-grid), skipping the colored banner/wave
  divider for both
- Cap hero section height at 700px via max-h to prevent it dominating
  ultra-wide viewports
- Watch selectedCategoryId in GalleryView and swap the hero photo to
  the category's hero_photo_id when filtering, reverting to the event
  default when cleared
- Add minimal/none preview branches in GalleryPreview so the admin
  theme editor shows visually distinct previews for all four styles
- Remove unused AdminPhoto import that was blocking the build
- Add Playwright e2e tests covering all four header styles, hero max
  height, and category hero switching
This commit is contained in:
Paul Nothaft
2026-02-04 08:30:55 +01:00
parent a19e7c40a2
commit bc6c48bb24
6 changed files with 510 additions and 19 deletions
@@ -3,7 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { Plus, X, Loader2, Image as ImageIcon, Check } from 'lucide-react';
import { toast } from 'react-toastify';
import { categoriesService, type PhotoCategory } from '../../services/categories.service';
import { photosService, type AdminPhoto } from '../../services/photos.service';
import { photosService } from '../../services/photos.service';
import { Button, Card, AuthenticatedImage } from '../common';
import { useTranslation } from 'react-i18next';
@@ -92,8 +92,10 @@ export const GalleryPreview: React.FC<GalleryPreviewProps> = ({
? 'justify-end text-right flex-row-reverse'
: 'justify-start text-left';
// Check if hero header style is selected
// Check header style
const isHeroHeader = theme.headerStyle === 'hero';
const isMinimalHeader = theme.headerStyle === 'minimal';
const isNoHeader = theme.headerStyle === 'none';
const heroDividerStyle: HeroDividerStyle = theme.heroDividerStyle || 'wave';
// Render hero divider based on style
@@ -210,7 +212,7 @@ export const GalleryPreview: React.FC<GalleryPreviewProps> = ({
fontFamily: theme.fontFamily || 'Inter, sans-serif',
}}
>
{/* Hero Header - shown when headerStyle is 'hero' */}
{/* Hero Header */}
{isHeroHeader && (
<div
className="relative text-white overflow-hidden"
@@ -221,7 +223,6 @@ export const GalleryPreview: React.FC<GalleryPreviewProps> = ({
>
<div className="py-8 px-4 relative z-10">
<div className="text-center max-w-md mx-auto">
{/* Logo in Hero */}
{showLogo && (
<div className="mb-3">
{resolvedLogoUrl ? (
@@ -238,7 +239,6 @@ export const GalleryPreview: React.FC<GalleryPreviewProps> = ({
)}
</div>
)}
{/* Event Name */}
<h1
className="text-xl font-bold mb-2"
style={{
@@ -248,22 +248,20 @@ export const GalleryPreview: React.FC<GalleryPreviewProps> = ({
>
Sample Event
</h1>
{/* Event Date */}
<div className="flex items-center justify-center text-white/80 text-sm" style={{ textShadow: '0 1px 3px rgba(0, 0, 0, 0.3)' }}>
<Calendar className="w-4 h-4 mr-1" />
<span>January 15, 2026</span>
</div>
</div>
</div>
{/* Divider */}
<div className="absolute bottom-0 left-0 right-0">
{renderHeroDivider()}
</div>
</div>
)}
{/* Standard Header - shown when headerStyle is NOT 'hero' */}
{!isHeroHeader && (
{/* Standard Header */}
{!isHeroHeader && !isMinimalHeader && !isNoHeader && (
<div
className="px-4 py-3 border-b space-y-2"
style={{
@@ -299,10 +297,32 @@ export const GalleryPreview: React.FC<GalleryPreviewProps> = ({
</div>
)}
{/* Minimal Header - thin bar with just event name */}
{isMinimalHeader && (
<div
className="px-4 py-2 border-b"
style={{
borderColor: theme.primaryColor ? `${theme.primaryColor}20` : '#e5e7eb',
}}
>
<p
className="text-sm font-semibold truncate"
style={{
fontFamily: theme.headingFontFamily || theme.fontFamily || 'Inter, sans-serif',
}}
>
Sample Event
</p>
</div>
)}
{/* None Header - no header content at all */}
{/* (isNoHeader renders nothing here — goes straight to layout bar) */}
{/* Layout info bar */}
<div className="px-4 py-1 border-b text-xs text-neutral-500 flex justify-between" style={{ borderColor: theme.primaryColor ? `${theme.primaryColor}20` : '#e5e7eb' }}>
<span>Gallery preview</span>
<span className="capitalize">{isHeroHeader ? `Hero + ${activeLayout}` : `${activeLayout} layout`}</span>
<span className="capitalize">{isHeroHeader ? `Hero + ${activeLayout}` : isMinimalHeader ? `Minimal + ${activeLayout}` : isNoHeader ? `No header + ${activeLayout}` : `${activeLayout} layout`}</span>
</div>
{/* Preview Content */}