fix(dino): hero responsive at 820-1100px + mobile card slider replacing wheel at ≤640px
This commit is contained in:
parent
7cf0af6b74
commit
2c59ea9ab7
1 changed files with 182 additions and 1 deletions
|
|
@ -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>
|
||||
Довжина <b>{d.length}</b>
|
||||
</span>
|
||||
)}
|
||||
{d.height && (
|
||||
<span>
|
||||
Висота <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"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue