fix(dino): hero responsive at 820-1100px + mobile card slider replacing wheel at ≤640px

This commit is contained in:
Vadym Samoilenko 2026-06-03 13:01:25 +01:00
parent 7cf0af6b74
commit 2c59ea9ab7

View file

@ -1,7 +1,7 @@
'use client'
/* eslint-disable @next/next/no-img-element */
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useCart } from '@/context/CartContext'
import { ImageLightbox } from '@/components/ui/ImageLightbox'
@ -514,6 +514,7 @@ const DYNO_CSS = `
.dino-page .why-grid{grid-template-columns:1fr;}
.dino-page .acc-side{max-width:704px;}
.dino-page .hero-text h1{font-size:52px;}
.dino-page .hero-dino{width:min(580px,52vw);height:auto;right:-30px;top:10px;opacity:.8;}
}
@media(max-width:820px){
.dino-page .hero-dino{width:min(520px,80vw);height:auto;max-height:75vh;right:-20px;top:0;opacity:.8;}
@ -549,6 +550,58 @@ const DYNO_CSS = `
/* Prevent SVG wheel from creating horizontal scroll */
.dino-page .slider-section{overflow:hidden;}
}
/* ── Mobile dino card slider (≤640px) ── */
.dino-page .dino-card-slider{
display:none;position:relative;overflow:hidden;
background:var(--green);
}
.dino-page .dino-card-slider-track{
display:flex;transition:transform .4s cubic-bezier(.25,.46,.45,.94);
will-change:transform;
}
.dino-page .dino-card{
flex:0 0 100%;width:100%;min-height:340px;position:relative;
background-size:cover;background-position:center;background-repeat:no-repeat;
}
@media(orientation:landscape){
.dino-page .dino-card{min-height:220px;}
}
.dino-page .dino-card-overlay{
position:absolute;inset:0;
background:linear-gradient(to top,rgba(34,62,13,.92) 0%,rgba(34,62,13,.4) 50%,transparent 100%);
display:flex;flex-direction:column;justify-content:flex-end;
padding:20px 60px 52px;
}
.dino-page .dino-card-overlay h3{
color:#fff;font-family:var(--ff-head);font-weight:700;
font-size:24px;line-height:1.25;margin:0;
}
.dino-page .dino-card-overlay .dc-ver{
color:rgba(255,255,255,.85);font-size:14px;margin:4px 0 8px;
}
.dino-page .dino-card-overlay .dc-stats{
display:flex;gap:20px;color:#fff;font-size:14px;font-family:var(--ff-body);flex-wrap:wrap;
}
.dino-page .dino-card-overlay .dc-stats b{font-weight:700;}
.dino-page .dcs-arrows{
position:absolute;bottom:12px;right:14px;display:flex;gap:8px;z-index:5;
}
.dino-page .dcs-arrows .wheel-arrow{position:static;transform:none;width:40px;height:40px;}
.dino-page .dcs-arrows .wheel-arrow:active{transform:scale(.93);}
.dino-page .dcs-dots{
position:absolute;bottom:22px;left:16px;
display:flex;gap:6px;z-index:5;align-items:center;
}
.dino-page .dcs-dot{
width:7px;height:7px;border-radius:50%;border:none;padding:0;cursor:pointer;
background:rgba(255,255,255,.4);transition:width .2s,height .2s,background .2s;
}
.dino-page .dcs-dot.active{width:10px;height:10px;background:#fff;}
@media(max-width:640px){
.dino-page .dino-wheel{display:none;}
.dino-page .dino-card-slider{display:block;}
}
`
// ─── Component ────────────────────────────────────────────────────────────────
@ -609,6 +662,44 @@ export function DinoPageContent({
[reviewVideos]
)
// Mobile dino card slider — shown at ≤640px instead of the wheel
const [mobileActive, setMobileActive] = useState(0)
const mobileTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)
const mobilePrev = useCallback(
() => setMobileActive((i) => (i - 1 + dinoList.length) % dinoList.length),
[dinoList.length]
)
const mobileNext = useCallback(
() => setMobileActive((i) => (i + 1) % dinoList.length),
[dinoList.length]
)
const resetMobileTimer = useCallback(() => {
if (mobileTimerRef.current) clearInterval(mobileTimerRef.current)
mobileTimerRef.current = setInterval(mobileNext, 3500)
}, [mobileNext])
useEffect(() => {
resetMobileTimer()
return () => {
if (mobileTimerRef.current) clearInterval(mobileTimerRef.current)
}
}, [resetMobileTimer])
const mobileSwipeStartX = useRef<number | null>(null)
const onMobileTouchStart = (e: React.TouchEvent) => {
mobileSwipeStartX.current = e.touches[0]?.clientX ?? null
}
const onMobileTouchEnd = (e: React.TouchEvent) => {
if (mobileSwipeStartX.current === null) return
const dx = (e.changedTouches[0]?.clientX ?? 0) - mobileSwipeStartX.current
if (Math.abs(dx) > 40) {
dx < 0 ? mobileNext() : mobilePrev()
resetMobileTimer()
}
mobileSwipeStartX.current = null
}
// fetch tariffs
useEffect(() => {
fetch('/api/tickets/tariffs')
@ -936,6 +1027,96 @@ export function DinoPageContent({
{/* ── DINO WHEEL + GALLERY ── */}
<section className="slider-section">
{/* ── MOBILE CARD SLIDER (≤640px) ── */}
<div
className="dino-card-slider"
onTouchStart={onMobileTouchStart}
onTouchEnd={onMobileTouchEnd}
>
<div
className="dino-card-slider-track"
style={{ transform: `translateX(-${mobileActive * 100}%)` }}
>
{dinoList.map((d, i) => (
<div
key={i}
className="dino-card"
style={{ backgroundImage: d.imageUrl ? `url(${d.imageUrl})` : undefined }}
>
<div className="dino-card-overlay">
<h3>{d.name}</h3>
{d.ver && <div className="dc-ver">{d.ver}</div>}
<div className="dc-stats">
{d.length && (
<span>
Довжина&nbsp;<b>{d.length}</b>
</span>
)}
{d.height && (
<span>
Висота&nbsp;<b>{d.height}</b>
</span>
)}
</div>
</div>
</div>
))}
</div>
<div className="dcs-dots">
{dinoList.map((_, i) => (
<button
key={i}
className={`dcs-dot${i === mobileActive ? 'active' : ''}`}
aria-label={`Динозавр ${i + 1}`}
onClick={() => {
setMobileActive(i)
resetMobileTimer()
}}
/>
))}
</div>
<div className="dcs-arrows">
<button
className="wheel-arrow prev"
aria-label="Попередній динозавр"
onClick={() => {
mobilePrev()
resetMobileTimer()
}}
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.4"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline points="15 18 9 12 15 6" />
</svg>
</button>
<button
className="wheel-arrow next"
aria-label="Наступний динозавр"
onClick={() => {
mobileNext()
resetMobileTimer()
}}
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.4"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline points="9 18 15 12 9 6" />
</svg>
</button>
</div>
</div>
<div
className="dino-wheel"
id="dp-dino-wheel"