diff --git a/src/app/(frontend)/page.tsx b/src/app/(frontend)/page.tsx
index 7f68bcc..6229f75 100644
--- a/src/app/(frontend)/page.tsx
+++ b/src/app/(frontend)/page.tsx
@@ -27,7 +27,8 @@ export default async function HomePage() {
// Fail gracefully — DB may not be available during static build
}
- const hero = home?.hero ?? STATIC_HERO
+ const heroData = home?.hero
+ const hero = heroData?.title ? heroData : STATIC_HERO
return (
diff --git a/src/app/(payload)/layout.tsx b/src/app/(payload)/layout.tsx
index f353bd8..49934ba 100644
--- a/src/app/(payload)/layout.tsx
+++ b/src/app/(payload)/layout.tsx
@@ -1,3 +1,4 @@
+import '@payloadcms/next/css'
import React from 'react'
import { RootLayout, handleServerFunctions } from '@payloadcms/next/layouts'
import type { ServerFunctionClient } from 'payload'
@@ -19,11 +20,7 @@ const serverFunction: ServerFunctionClient = async function (args) {
export default function PayloadLayout({ children }: { children: React.ReactNode }) {
return (
-
+
{children}
)
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index f1a0385..8c5c674 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,6 +1,5 @@
import React from 'react'
import type { Metadata } from 'next'
-import './globals.css'
export const metadata: Metadata = {
title: 'Shumiland',
@@ -8,7 +7,10 @@ export const metadata: Metadata = {
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
-
+
+
+
+
{children}
)
diff --git a/src/components/sections/Gallery.tsx b/src/components/sections/Gallery.tsx
index 7556c91..752b4d5 100644
--- a/src/components/sections/Gallery.tsx
+++ b/src/components/sections/Gallery.tsx
@@ -2,15 +2,16 @@ import { GallerySlider } from './GallerySlider'
import type { GalleryImage } from './GallerySlider'
const IMAGES: GalleryImage[] = [
- { src: '/images/figma/gallery-2.png', alt: 'Шуміленд — фото 1' },
- { src: '/images/figma/gallery-4.png', alt: 'Шуміленд — фото 2' },
- { src: '/images/figma/gallery-6.png', alt: 'Шуміленд — фото 3' },
- { src: '/images/figma/gallery-7.png', alt: 'Шуміленд — фото 4' },
- { src: '/images/figma/loc-map.jpg', alt: 'Шуміленд — фото 5', width: 592, height: 427, radius: 30 },
- { src: '/images/figma/gallery-8.png', alt: 'Шуміленд — фото 6' },
- { src: '/images/figma/hero-bg-family.png', alt: 'Шуміленд — фото 7' },
- { src: '/images/figma/why-parents-1.png', alt: 'Шуміленд — фото 8' },
- { src: '/images/figma/video-preview.png', alt: 'Шуміленд — фото 9' },
+ { src: '/images/figma/why-parents-1.png', alt: 'Шуміленд — сімейні враження', width: 320, height: 420, radius: 20 },
+ { src: '/images/figma/gallery-6.png', alt: 'Шуміленд — атракціони', width: 380, height: 420, radius: 20 },
+ { src: '/images/figma/gallery-7.png', alt: 'Шуміленд — фото 3', width: 320, height: 420, radius: 20 },
+ { src: '/images/figma/why-parents-2.png', alt: 'Шуміленд — прогулянка', width: 380, height: 420, radius: 20 },
+ { src: '/images/figma/news-bg2.png', alt: 'Шуміленд — зони парку', width: 320, height: 420, radius: 20 },
+ { src: '/images/figma/gallery-4.png', alt: 'Шуміленд — фото 5', width: 380, height: 420, radius: 20 },
+ { src: '/images/figma/why-parents-3.png', alt: 'Шуміленд — відпочинок', width: 320, height: 420, radius: 20 },
+ { src: '/images/figma/gallery-2.png', alt: 'Шуміленд — фото 7', width: 380, height: 420, radius: 20 },
+ { src: '/images/figma/news-bg6.png', alt: 'Шуміленд — Шумі Кафе', width: 320, height: 420, radius: 20 },
+ { src: '/images/figma/why-parents-4.png', alt: 'Шуміленд — карта парку', width: 380, height: 420, radius: 20 },
]
export function Gallery() {
@@ -26,7 +27,7 @@ export function Gallery() {
-
+
)
diff --git a/src/components/sections/GallerySlider.tsx b/src/components/sections/GallerySlider.tsx
index 7069625..ee4cf66 100644
--- a/src/components/sections/GallerySlider.tsx
+++ b/src/components/sections/GallerySlider.tsx
@@ -1,8 +1,7 @@
'use client'
/* eslint-disable @next/next/no-img-element */
-import { useRef } from 'react'
-import { useAutoScroll } from '@/hooks/useAutoScroll'
+import { useState } from 'react'
export interface GalleryImage {
src: string
@@ -14,62 +13,65 @@ export interface GalleryImage {
interface GallerySliderProps {
images: GalleryImage[]
+ speed?: number
}
-export function GallerySlider({ images }: GallerySliderProps) {
- const trackRef = useRef
(null)
- useAutoScroll(trackRef, { speed: 0.5, intervalMs: 16 })
+export function GallerySlider({ images, speed = 35 }: GallerySliderProps) {
+ const [paused, setPaused] = useState(false)
- function scrollByOne(dir: 1 | -1) {
- trackRef.current?.scrollBy({ left: dir * 710, behavior: 'smooth' })
- }
+ // Duplicate for seamless infinite loop
+ const doubled = [...images, ...images]
return (
-
-
+
setPaused(true)}
+ onMouseLeave={() => setPaused(false)}
+ >
+
- {images.map((img, i) => {
- const w = img.width ?? 684
- const h = img.height ?? 494
- const r = img.radius ?? 35
+ {doubled.map((img, i) => {
+ const w = img.width ?? 384
+ const h = img.height ?? 280
+ const r = img.radius ?? 20
return (
)
})}
-
-
)
}
diff --git a/src/components/sections/Hero.test.tsx b/src/components/sections/Hero.test.tsx
index fb64a69..8256c47 100644
--- a/src/components/sections/Hero.test.tsx
+++ b/src/components/sections/Hero.test.tsx
@@ -60,7 +60,9 @@ describe('Hero', () => {
it('renders title when provided', () => {
const hero: HomePageHero = { title: 'Welcome to Shumiland' }
render(
)
- expect(screen.getByRole('heading', { level: 1, name: 'Welcome to Shumiland' })).toBeInTheDocument()
+ expect(
+ screen.getByRole('heading', { level: 1, name: 'Welcome to Shumiland' })
+ ).toBeInTheDocument()
})
it('does not render a heading when title is not provided', () => {
diff --git a/src/components/sections/Hero.tsx b/src/components/sections/Hero.tsx
index 9dd10f8..fbdaf46 100644
--- a/src/components/sections/Hero.tsx
+++ b/src/components/sections/Hero.tsx
@@ -3,7 +3,6 @@ import type { HomePageHero, Media } from '@/types/globals'
import { BtnPrimary } from '@/components/ui/BtnPrimary'
const IMG_BG2 = '/images/figma/hero-bg2.png'
-const IMG_BG1 = '/images/figma/hero-bg1.png'
const IMG_FAMILY = '/images/figma/hero-bg-family.png'
interface HeroProps {
@@ -27,7 +26,7 @@ export function Hero({ hero }: HeroProps) {
return (
{/* Background layers */}
@@ -39,19 +38,28 @@ export function Hero({ hero }: HeroProps) {
muted
playsInline
aria-hidden="true"
- className="absolute inset-0 w-full h-full object-cover pointer-events-none"
+ className="pointer-events-none absolute inset-0 h-full w-full object-cover"
/>
) : bgMedia ? (
) : (
<>
-
-
-
+
+
>
)}
@@ -59,14 +67,14 @@ export function Hero({ hero }: HeroProps) {
The mobile layout is always in the DOM; CSS hides it visually on desktop. */}
{/* L-shaped frosted layer */}
{title && (
-
+
+
{/* Mobile / tablet — semantic layout (always in DOM, provides accessible content) */}
-
-
+
+
{title && (
{title}
@@ -149,7 +151,7 @@ export function Hero({ hero }: HeroProps) {
)}
{subtitle && (
{subtitle}
diff --git a/src/components/sections/Locations.tsx b/src/components/sections/Locations.tsx
index c6f9ead..6004bf7 100644
--- a/src/components/sections/Locations.tsx
+++ b/src/components/sections/Locations.tsx
@@ -1,17 +1,13 @@
import { LocationsSlider } from './LocationsSlider'
import type { LocationData } from './LocationsSlider'
-const IMG_DINOPARK = '/images/figma/loc-dinopark.jpg'
-const IMG_DIVO_LIS = '/images/figma/loc-divo-lis.png'
-const IMG_MAP = '/images/figma/loc-map.jpg'
-
const LOCATIONS: LocationData[] = [
{
name: 'ДиноПарк',
tagline: 'портал у світ динозаврів',
description:
'Ви бачили їх у фільмах та мультиках, а тепер час зустріти в реальному житті та роздивитися їх зблизька! Найбільші динозаври України, які гарчать і рухаються, як справжні, захопливі відкриття та атмосфера справжньої наукової експедиції.',
- image: IMG_DINOPARK,
+ image: '/images/figma/loc-dinopark.jpg',
href: '/lokatsii',
},
{
@@ -19,7 +15,7 @@ const LOCATIONS: LocationData[] = [
tagline: 'зона казкових топіарних фігур',
description:
'Тут на лісових стежках оселилися єдинороги, дракони та добрі лісові звірята. Це ідеальне місце, щоб пофантазувати разом із дитиною та придумати спільну яскраву історію.',
- image: IMG_DIVO_LIS,
+ image: '/images/figma/loc-divo-lis.png',
href: '/lokatsii',
},
{
@@ -27,7 +23,7 @@ const LOCATIONS: LocationData[] = [
tagline: 'справжній виклик кмітливості',
description:
'Чи зможете ви разом знайти вихід? Це справжній пригодницький виклик для всієї родини! Тут діти вчаться бути уважними та впевненими у собі, адже вони стають героями справжнього квесту.',
- image: IMG_MAP,
+ image: '/images/figma/news-bg3.jpg',
href: '/lokatsii',
},
{
@@ -35,7 +31,7 @@ const LOCATIONS: LocationData[] = [
tagline: 'перемога, яку ви розділите разом',
description:
'Для дітей це не просто гра, а можливість проявити себе та "заробити" подарунок. Влаштуйте дружні змагання, дайте малечі декілька уроків та виграйте класний приз.',
- image: IMG_MAP,
+ image: '/images/figma/news-bg4.png',
href: '/lokatsii',
},
{
@@ -43,7 +39,7 @@ const LOCATIONS: LocationData[] = [
tagline: 'територія забав і нових друзів',
description:
'Поки малеча підкорює гірки, випробовує безпечні лазанки та знаходить перших друзів, ви можете нарешті зробити паузу та просто спостерігати за їхніми розвагами.',
- image: IMG_MAP,
+ image: '/images/figma/news-bg5.png',
href: '/lokatsii',
},
]
diff --git a/src/components/sections/LocationsSlider.tsx b/src/components/sections/LocationsSlider.tsx
index 4bbf0d3..18edaa6 100644
--- a/src/components/sections/LocationsSlider.tsx
+++ b/src/components/sections/LocationsSlider.tsx
@@ -16,17 +16,9 @@ interface LocationsSliderProps {
locations: LocationData[]
}
-/**
- * Locations slider (Figma: 5 cards × 694w × 491h, gap 20).
- * - card width 694, height 491, rounded 20
- * - dark-green text panel 327 wide on the right of each card
- * (rgba(34,62,13,0.8) — partially transparent over the photo)
- * - auto-scrolls 1px/16ms (≈60 fps marquee), pauses on hover
- * - prev/next arrow buttons for manual nav
- */
export function LocationsSlider({ locations }: LocationsSliderProps) {
const trackRef = useRef(null)
- useAutoScroll(trackRef, { speed: 0.6, intervalMs: 16 })
+ useAutoScroll(trackRef, { speed: 0.5, intervalMs: 16 })
function scrollByOne(dir: 1 | -1) {
trackRef.current?.scrollBy({ left: dir * 714, behavior: 'smooth' })
@@ -36,7 +28,7 @@ export function LocationsSlider({ locations }: LocationsSliderProps) {
- {locations.map((loc) => (
-
-
-

-
-
-
- {loc.name}
-
-
- {loc.tagline}
-
-
- {loc.description}
-
+
+ {locations.map((loc) => (
+
+
+

+
+
+
+ {loc.name}
+
+
+ {loc.tagline}
+
+
+ {loc.description}
+
+
+
Купити квиток
-
Купити квиток
-
-
- ))}
+
+ ))}
+