132 lines
5.2 KiB
TypeScript
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>
|
|
)
|
|
}
|