visitapp-web/src/components/sections/SliderSection.tsx
2026-05-07 15:28:48 +02:00

132 lines
5.2 KiB
TypeScript

'use client'
import { useEffect, useState } from 'react'
import Image from 'next/image'
import { useRouter } from 'next/navigation'
import { useVisitor } from '@/context/VisitorContext'
import { t, tPlain } from '@/lib/i18n'
import type { SectionDTO } from '@/lib/api/types'
import AppBar from '@/components/ui/AppBar'
interface Props {
section: SectionDTO
slug: string
configId: string
languages: string[]
}
export default function SliderSection({ section, languages }: Props) {
const { language, setAvailableLanguages } = useVisitor()
const router = useRouter()
const [index, setIndex] = useState(0)
useEffect(() => { setAvailableLanguages(languages) }, [languages])
const contents = [...(section.slider?.contents ?? [])]
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
if (contents.length === 0) {
return (
<div style={{ position: 'fixed', inset: 0, display: 'flex', flexDirection: 'column', background: 'var(--color-background)' }}>
<AppBar title={tPlain(section.title, language)} onBack={() => router.back()} />
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, color: 'var(--color-text-muted)' }}>
Aucun contenu à afficher
</div>
</div>
)
}
const current = contents[index]
return (
<div style={{ position: 'fixed', inset: 0, display: 'flex', flexDirection: 'column', background: 'var(--color-background)' }}>
<AppBar title={tPlain(section.title, language)} onBack={() => router.back()} />
<main style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
{/* Image zone — ~75% of remaining height */}
<div style={{ flex: 3, minHeight: 0, position: 'relative' }}>
{current?.resource?.url && (
<Image
src={current.resource.url}
alt={tPlain(current.title, language)}
fill
className="object-contain"
sizes="100vw"
/>
)}
{/* Title overlay */}
{tPlain(current?.title, language) && (
<div
style={{ position: 'absolute', bottom: 0, left: 0, right: 0, padding: '12px 16px', background: 'linear-gradient(to top, rgba(0,0,0,0.6), transparent)' }}
>
<p style={{ color: 'white', fontSize: 16, fontWeight: 600, margin: 0 }}>
{tPlain(current?.title, language)}
</p>
</div>
)}
{/* Prev / Next arrows */}
{contents.length > 1 && (
<>
<button
onClick={() => setIndex((i) => Math.max(0, i - 1))}
disabled={index === 0}
style={{ position: 'absolute', left: 8, top: '50%', transform: 'translateY(-50%)', background: 'rgba(0,0,0,0.4)', color: 'white', borderRadius: '50%', padding: 8, border: 'none', cursor: 'pointer', opacity: index === 0 ? 0.2 : 1, display: 'flex' }}
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
</svg>
</button>
<button
onClick={() => setIndex((i) => Math.min(contents.length - 1, i + 1))}
disabled={index === contents.length - 1}
style={{ position: 'absolute', right: 8, top: '50%', transform: 'translateY(-50%)', background: 'rgba(0,0,0,0.4)', color: 'white', borderRadius: '50%', padding: 8, border: 'none', cursor: 'pointer', opacity: index === contents.length - 1 ? 0.2 : 1, display: 'flex' }}
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
</svg>
</button>
</>
)}
</div>
{/* Description card */}
{t(current?.description, language) && (
<div
style={{ flex: 1, minHeight: 0, overflowY: 'auto', margin: '12px 16px', borderRadius: 16, padding: 16, background: 'var(--color-surface)', boxShadow: '0 2px 8px rgba(0,0,0,0.08)', flexShrink: 0 }}
>
<div
className="prose prose-sm text-center max-w-none"
style={{ color: 'var(--color-text)' }}
dangerouslySetInnerHTML={{ __html: t(current?.description, language) }}
/>
</div>
)}
{/* Dots indicator */}
{contents.length > 1 && (
<div style={{ flexShrink: 0, display: 'flex', justifyContent: 'center', gap: 6, padding: '12px 0' }}>
{contents.map((_, i) => (
<button
key={i}
onClick={() => setIndex(i)}
style={{
borderRadius: 9999,
border: 'none',
cursor: 'pointer',
transition: 'all 0.2s',
width: i === index ? 20 : 8,
height: 8,
background: i === index ? 'var(--color-primary)' : 'var(--color-border)',
padding: 0,
}}
/>
))}
</div>
)}
</main>
</div>
)
}