11import Image from "next/image" ;
2- import { Badge } from "@techsio/ui-kit/atoms/badge" ;
3- import { Link } from "@techsio/ui-kit/atoms/link" ;
42import {
53 Carousel ,
64 type CarouselSlide ,
75} from "@techsio/ui-kit/molecules/carousel" ;
86import NextLink from "next/link" ;
97import { useMemo } from "react" ;
10- import { HERO_PAGE_SIZE , type HeroBannerItem } from "@/components/homepage/homepage.data" ;
8+ import {
9+ HERO_PAGE_SIZE ,
10+ type HeroBannerItem ,
11+ } from "@/components/homepage/homepage.data" ;
12+ import { Button } from "@techsio/ui-kit/atoms/button" ;
13+
14+ const HERO_CTA_LABEL = "Zistiť viac" ;
15+ const HERO_DESKTOP_SLIDES_PER_PAGE = 4.1 ;
16+ const HERO_DESKTOP_SLIDE_SPACING = "var(--spacing-400)" ;
17+
18+ function HeroBannerCard ( { banner } : { banner : HeroBannerItem } ) {
19+ return (
20+ < NextLink
21+ aria-label = { `${ banner . title } - ${ HERO_CTA_LABEL } ` }
22+ className = "group relative h-full overflow-hidden rounded-lg bg-fg-primary shadow-sm font-open-sans"
23+ href = { banner . href }
24+ >
25+ < Image
26+ alt = { banner . id }
27+ className = "object-cover transition-transform duration-500 group-hover:scale-105"
28+ fill
29+ src = { banner . imageSrc }
30+ />
31+ < div className = "absolute inset-0 bg-gradient-to-t from-fg-primary/85 via-fg-primary/35 to-transparent" />
32+ { banner . title && < div className = "absolute inset-x-0 bottom-0 flex flex-col items-start p-600 text-fg-reverse" >
33+ < p className = "line-clamp-2 text-2xl leading-[26px] font-bold" >
34+ { banner . title }
35+ </ p >
36+ { banner . subtitle && (
37+ < p className = "line-clamp-2 text-md leading-snug font-semibold text-fg-reverse" >
38+ { banner . subtitle }
39+ </ p >
40+ ) }
41+ < Button size = "md" className = "mt-350 rounded-xl py-250 px-450 text-md" >
42+ { HERO_CTA_LABEL }
43+ </ Button >
44+ </ div > }
45+ </ NextLink >
46+ ) ;
47+ }
1148
1249const buildHeroSlides = ( banners : HeroBannerItem [ ] ) : CarouselSlide [ ] => {
1350 const slides : CarouselSlide [ ] = [ ] ;
@@ -19,35 +56,9 @@ const buildHeroSlides = (banners: HeroBannerItem[]): CarouselSlide[] => {
1956 slides . push ( {
2057 id : `hero-page-${ pageIndex } ` ,
2158 content : (
22- < div className = "grid h-full w-full grid-cols-2 gap-300 lg:grid-cols-4" >
59+ < div className = "grid h-full w-full grid-cols-2 gap-400 lg:grid-cols-4" >
2360 { page . map ( ( banner ) => (
24- < NextLink
25- className = "group relative h-full overflow-hidden rounded-2xl border border-border-secondary"
26- href = { banner . href }
27- key = { banner . id }
28- >
29- < Image
30- alt = { banner . title }
31- fill
32- className = "object-cover transition-transform duration-300 group-hover:scale-105"
33- src = { banner . imageSrc }
34- />
35- < div className = "absolute inset-0 bg-gradient-to-t from-fg-primary/70 via-fg-primary/20 to-transparent" />
36- < div className = "absolute inset-x-0 bottom-0 p-300 text-fg-reverse" >
37- < Badge
38- className = "mb-100 rounded-full px-200 py-50 text-2xs font-semibold uppercase"
39- variant = "secondary"
40- >
41- { banner . badge }
42- </ Badge >
43- < p className = "line-clamp-2 text-sm leading-tight font-bold" >
44- { banner . title }
45- </ p >
46- < p className = "line-clamp-2 text-xs text-fg-reverse/85" >
47- { banner . subtitle }
48- </ p >
49- </ div >
50- </ NextLink >
61+ < HeroBannerCard banner = { banner } key = { banner . id } />
5162 ) ) }
5263 </ div >
5364 ) ,
@@ -57,28 +68,74 @@ const buildHeroSlides = (banners: HeroBannerItem[]): CarouselSlide[] => {
5768 return slides ;
5869} ;
5970
71+ const buildHeroDesktopSlides = (
72+ banners : HeroBannerItem [ ] ,
73+ ) : CarouselSlide [ ] =>
74+ banners . map ( ( banner ) => ( {
75+ id : banner . id ,
76+ content : < HeroBannerCard banner = { banner } /> ,
77+ } ) ) ;
78+
6079type HomepageHeroCarouselSectionProps = {
6180 banners : HeroBannerItem [ ] ;
6281} ;
6382
83+ type HeroCarouselProps = {
84+ slides : CarouselSlide [ ] ;
85+ slidesPerPage ?: number ;
86+ spacing ?: string ;
87+ } ;
88+
89+ function HeroCarousel ( {
90+ slides,
91+ slidesPerPage = 1 ,
92+ spacing = "0px" ,
93+ } : HeroCarouselProps ) {
94+ const hasOverflow = slides . length > slidesPerPage ;
95+
96+ return (
97+ < Carousel . Root
98+ aspectRatio = "none"
99+ className = "w-full"
100+ loop = { hasOverflow }
101+ size = "full"
102+ slideCount = { slides . length }
103+ slidesPerMove = { 1 }
104+ slidesPerPage = { slidesPerPage }
105+ spacing = { spacing }
106+ >
107+ < Carousel . Slides className = "h-homepage-hero-carousel" slides = { slides } />
108+ { hasOverflow ? (
109+ < >
110+ < Carousel . Previous className = "-translate-y-1/2 absolute top-1/2 left-200 rounded-full aspect-square shadow-carousel-trigger active:text-carousel-trigger-fg-active" />
111+ < Carousel . Next className = "-translate-y-1/2 absolute top-1/2 right-200 rounded-full aspect-square shadow-carousel-trigger active:text-carousel-trigger-fg-active" />
112+ </ >
113+ ) : null }
114+ </ Carousel . Root >
115+ ) ;
116+ }
117+
64118export function HomepageHeroCarouselSection ( {
65119 banners,
66120} : HomepageHeroCarouselSectionProps ) {
67121 const slides = useMemo ( ( ) => buildHeroSlides ( banners ) , [ banners ] ) ;
122+ const desktopSlides = useMemo (
123+ ( ) => buildHeroDesktopSlides ( banners ) ,
124+ [ banners ] ,
125+ ) ;
68126
69127 return (
70128 < section >
71- < Carousel . Root
72- aspectRatio = "none"
73- className = "w-full"
74- loop
75- slideCount = { slides . length }
76- size = "full"
77- >
78- < Carousel . Slides className = "h-120" slides = { slides } />
79- < Carousel . Previous className = "-translate-y-1/2 absolute top-1/2 left-200 rounded-full border border-surface/80 aspect-square font-bold" />
80- < Carousel . Next className = "-translate-y-1/2 absolute top-1/2 right-200 rounded-full border border-surface/80 aspect-square font-bold" />
81- </ Carousel . Root >
129+ < div className = "xl:hidden" >
130+ < HeroCarousel slides = { slides } />
131+ </ div >
132+ < div className = "hidden xl:block" >
133+ < HeroCarousel
134+ slides = { desktopSlides }
135+ slidesPerPage = { HERO_DESKTOP_SLIDES_PER_PAGE }
136+ spacing = { HERO_DESKTOP_SLIDE_SPACING }
137+ />
138+ </ div >
82139 </ section >
83140 ) ;
84141}
0 commit comments