<section class="news">
<div class="container">
<h2 class="news-title">Látásmódunk - néhány kiragadott példán keresztül</h2>
<div class="news-swiper">
<!-- Swiper Container -->
<swiper-container
#swiperRef
[slidesPerView]="1"
[spaceBetween]="10"
[loop]="true"
autoplay-delay="3000"
autoplay-disable-on-interaction="true"
autoplay-pause-on-mouse-enter="true"
>
<swiper-slide *ngFor="let news of newsItems">
<article class="news-card">
<div class="news-card-overlay"></div>
<picture>
<source media="(min-width: 1200px)" [srcset]="news.img_xl">
<source media="(min-width: 992px)" [srcset]="news.img_lg">
<source media="(min-width: 768px)" [srcset]="news.img_md">
<img class="news-image" [src]="news.img_sm" [alt]="news.alt" />
</picture>
<div class="news-caption">
<h3 class="news-caption-title">{{ news.title }}</h3>
<app-button [link]="news.link" [label]="'CTA.READMORE' | transloco"></app-button>
</div>
</article>
</swiper-slide>
</swiper-container>
<!-- Custom Pagination -->
<div class="news-pagination">
<div
class="pagination-item"
*ngFor="let news of newsItems; let i = index"
[class.active]="i === activeIndex"
(click)="setActiveSlide(i)"
>
<span class="pagination-progress" [class.running]="i === activeIndex"></span>
<span class="pagination-label">
{{ news.title }}
</span>
</div>
</div>
<span class="news-swiper-overlay"></span>
</div>
</div>
</section>
import { Component, CUSTOM_ELEMENTS_SCHEMA, PLATFORM_ID, Inject, ViewChild, ElementRef } from '@angular/core';
import { ButtonComponent } from '../../../../shared/components';
import { TranslocoPipe } from '@jsverse/transloco';
import { MockNews } from './news.mock';
import { News } from './news.model';
import { CommonModule, isPlatformBrowser } from '@angular/common';
import { register, SwiperContainer } from 'swiper/element/bundle';
register();
@Component({
selector: 'app-news',
imports: [CommonModule, ButtonComponent, TranslocoPipe],
templateUrl: './news.component.html',
styleUrl: './news.component.scss',
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class NewsComponent {
@ViewChild('swiperRef', { static: true })
protected _swiperRef!: ElementRef<HTMLElement>;
newsItems: readonly News[] = MockNews;
activeIndex: number = 0;
constructor(@Inject(PLATFORM_ID) private platformId: object) {}
ngAfterViewInit() {
if (!isPlatformBrowser(this.platformId)) return;
const el = this._swiperRef.nativeElement as any;
el.addEventListener('slidechange', (e: any) => {
this.activeIndex = e.detail[0].realIndex;
});
el.initialize();
}
setActiveSlide(idx: number) {
if (!isPlatformBrowser(this.platformId)) return;
const swiper = (this._swiperRef.nativeElement as any).swiper;
swiper.slideToLoop(idx);
this.activeIndex = idx;
}
}
@use "shared" as *;
.news{
background: var(--color-black);
color: var(--color-white);
&-swiper{
position: relative;
padding-bottom: 80px;
}
&-title{
font-size: 32px;
text-align: center;
line-height: 120%;
margin-bottom: 48px;
@include media-breakpoint-up(md){
font-size: 40px;
}
}
&-card {
position: relative;
display: inline-block;
width: 100%;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 8px 24px rgba(0,0,0,0.2);
&-overlay{
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.9) 70%);
position: absolute;
width: 100%;
height: 70%;
bottom: 0;
left: 0;
z-index: 9;
}
}
&-image {
display: block;
width: 100%;
height: auto;
object-fit: cover;
}
&-caption {
position: absolute;
bottom: 100px;
left: 0px;
right: 20px;
text-align: left;
padding: 60px 24px 32px;
width: 100%;
z-index: 9;
@include media-breakpoint-up(md){
padding: 60px 32px 40px;
}
&-title {
font-weight: bold;
line-height: 1.2;
margin-bottom: 24px;
font-size: 20px;
position: relative;
z-index: 999;
@include media-breakpoint-up(md){
font-size: 24px;
max-width: 423px;
}
}
}
&-pagination {
position: absolute;
bottom: 110px;
left: 32px;
display: flex;
justify-content: space-between;
padding: 0;
gap: 16px;
margin-top: 32px;
z-index: 9;
@include media-breakpoint-up(md){
margin-top: 45px;
}
@include media-breakpoint-up(lg){
margin-top: 48px;
gap: 32px;
}
.pagination-item {
flex: 1;
position: relative;
cursor: pointer;
border-top: 2px solid var(--color-grey-400);
transition: opacity 0.3s, border-color 0.3s;
width: 100%;
.pagination-progress {
position: absolute;
top: -2px;
left: 0;
height: 2px;
width: 0;
background-color: var(--color-primary);
transition: width 1s;
}
.pagination-label {
display: none;
@include media-breakpoint-up(lg){
display: block;
font-size: 14px;
line-height: 1.4;
color: var(--color-grey-400);
display: block;
margin-top: 8px;
}
}
&.active,
&:hover {
opacity: 1;
border-top-color: var(--color-primary);
.pagination{
&-progress {
width: 100%;
}
&-label{
color: var(--color-white);
}
}
}
}
.pagination-item.active .pagination-progress {
background-color: var(--color-primary);
}
}
}
swiper-container {
width: 100%;
}
swiper-slide {
display: flex;
justify-content: center;
align-items: center;
font-size: 1.5rem;
}