-
+ <>
+
+
+
-
- {(m: MediaItem) => (
+
+
+
+ {(m: MediaItem) => (
+
+
+ )}
+
+
+
+
+
-
-
+
+
-
-
- {props.article.title}
-{capitalize(props.article.subtitle, false)}
-{props.article.title}
+{capitalize(props.article.subtitle, false)}
+
-
- {(a: Author, index) => (
- <>
- 0}>,
- {a.name}
- >
- )}
-
-
-
-
+
+ {(a: Author, index) => (
<>
-
-
+ 0}>,
+ {a.name}
>
)}
-
- }
- >
-
+
+
+
+
+
+
+
-
- {(m: MediaItem) => (
-
+
+
-
-
-
-
+
+
+
+
+ {(m: MediaItem) => (
+
+
+
+
+
+
+
+
+ )}
+
+ }>
+
+
+
+
+
+
- ()
+ const [swiperThumbs, setSwiperThumbs] = createSignal()
+
const opts: SwiperOptions = {
+ lazy: true,
roundLengths: true,
loop: true,
centeredSlides: true,
slidesPerView: 1,
- modules: [Navigation, Pagination],
+ modules: [Navigation, Pagination, Lazy, Thumbs],
speed: 500,
navigation: { nextEl, prevEl },
- pagination: {
- el: pagEl,
- type: 'bullets',
- clickable: true
- },
breakpoints: {
768: {
slidesPerView: props.slidesPerView > 0 ? props.slidesPerView : 1.66666,
@@ -44,13 +50,48 @@ export default (props: SliderProps) => {
slidesPerView: props.slidesPerView > 0 ? props.slidesPerView : 1.66666,
spaceBetween: isCardsWithCover ? 8 : 52
}
+ },
+ thumbs: {
+ swiper: swiperThumbs()
}
}
- const [swiper, setSwiper] = createSignal()
+ createEffect(() => {
+ if (props.hasThumbs && !!thumbsEl) {
+ setTimeout(() => {
+ setSwiperThumbs(
+ new Swiper(thumbsEl, {
+ slidesPerView: 'auto',
+ modules: [Lazy, Thumbs],
+ lazy: true,
+ roundLengths: true,
+ spaceBetween: 20,
+ freeMode: true,
+ breakpoints: {
+ 768: {
+ direction: 'vertical'
+ }
+ }
+ })
+ )
+ }, 500)
+ }
+ })
+
createEffect(() => {
if (!swiper() && !!el) {
setTimeout(() => {
+ if (swiperThumbs()) {
+ opts.thumbs = {
+ swiper: swiperThumbs()
+ }
+
+ opts.pagination = {
+ el: '.swiper-pagination',
+ type: 'fraction'
+ }
+ }
+
setSwiper(new Swiper(el, opts))
}, 500)
}
@@ -61,15 +102,33 @@ export default (props: SliderProps) => {
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {props.article.stat?.viewed}
+
+
+
+ {props.article.stat?.commented || ''}
+
+
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+ {formattedDate()}
+
+
+
+
+
+
+
+
+
+
+
+
+ {(topic) => (
+
)}
-
-
- }>
-
+
+
+ >
)
}
diff --git a/src/components/_shared/Slider.scss b/src/components/_shared/Slider.scss
index 3b739647..6d11f0f6 100644
--- a/src/components/_shared/Slider.scss
+++ b/src/components/_shared/Slider.scss
@@ -1,6 +1,5 @@
.swiper-slide {
min-height: 0 !important;
- margin-bottom: 0 !important;
.cards-with-cover & {
height: 0 !important;
@@ -13,6 +12,16 @@
@include media-breakpoint-up(md) {
padding-top: 35% !important;
}
+
+ img {
+ height: 100%;
+ left: 0;
+ object-fit: cover;
+ object-position: center;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ }
}
}
@@ -88,3 +97,117 @@
}
}
}
+
+.swiper--page-gallery {
+ padding-bottom: 4rem;
+
+ .swiper-wrapper {
+ align-items: center;
+ }
+
+ .swiper-slide {
+ display: flex;
+ justify-content: center;
+ }
+
+ .swiper-slide__inner {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+
+ img {
+ display: block;
+ height: auto;
+ margin: 0 auto;
+ max-height: 80vh;
+ width: auto;
+ position: relative;
+ z-index: 11;
+ }
+ }
+
+ .slider-arrow-prev,
+ .slider-arrow-next {
+ background: rgb(0 0 0 / 0.2);
+ width: 5rem;
+ }
+
+ .slider-arrow-next .icon {
+ margin-right: 2rem;
+ }
+
+ .slider-arrow-prev .icon {
+ margin-left: 2rem;
+ }
+
+ .swiper-slide-active {
+ .swiper-lazy-preloader {
+ display: none;
+ }
+ }
+}
+
+.thumbs-container {
+ @include media-breakpoint-up(md) {
+ padding-left: 3.2rem;
+ }
+}
+
+.swiper--thumbs {
+ @include media-breakpoint-up(md) {
+ max-height: 80vh;
+ min-width: 100px;
+ padding: 0 !important;
+ width: 100px !important;
+ }
+
+ .swiper-slide {
+ cursor: pointer;
+ height: 80px;
+ opacity: 0.5;
+ width: 100px;
+
+ @include media-breakpoint-up(md) {
+ height: 52px;
+ width: auto;
+ }
+
+ img {
+ height: 100%;
+ object-fit: cover;
+ object-position: center;
+ width: 100%;
+ }
+ }
+
+ .swiper-slide-thumb-active {
+ opacity: 1;
+ }
+
+ .swiper-slide__inner {
+ height: 100%;
+ flex: 1;
+ }
+
+ .swiper-lazy-preloader,
+ .image-description {
+ display: none;
+ }
+}
+
+.sliders-container {
+ @include media-breakpoint-up(md) {
+ display: flex;
+ }
+}
+
+.swiper-pagination {
+ background: #141414;
+ bottom: 0;
+ font-size: 1.2rem;
+ font-weight: bold;
+ left: auto;
+ right: 0;
+ padding: 1rem;
+ width: auto;
+}
diff --git a/src/components/_shared/Slider.tsx b/src/components/_shared/Slider.tsx
index 4ce2d38b..a520858e 100644
--- a/src/components/_shared/Slider.tsx
+++ b/src/components/_shared/Slider.tsx
@@ -1,40 +1,46 @@
-import { Swiper, Navigation, Pagination } from 'swiper'
+import { Swiper, Navigation, Pagination, Lazy, Thumbs } from 'swiper'
import type { SwiperOptions } from 'swiper'
import 'swiper/scss'
import 'swiper/scss/navigation'
import 'swiper/scss/pagination'
+import 'swiper/scss/lazy'
+import 'swiper/scss/thumbs'
import './Slider.scss'
-import { createEffect, createSignal, JSX } from 'solid-js'
+import { createEffect, createSignal, JSX, Show } from 'solid-js'
import { Icon } from './Icon'
+import { clsx } from 'clsx'
interface SliderProps {
title?: string
slidesPerView?: number
isCardsWithCover?: boolean
children?: JSX.Element
+ class?: string
+ isPageGallery?: boolean
+ hasThumbs?: boolean
}
export default (props: SliderProps) => {
let el: HTMLDivElement | undefined
+ let thumbsEl: HTMLDivElement | undefined
let pagEl: HTMLDivElement | undefined
let nextEl: HTMLDivElement | undefined
let prevEl: HTMLDivElement | undefined
const isCardsWithCover = typeof props.isCardsWithCover === 'boolean' ? props.isCardsWithCover : true
+ const [swiper, setSwiper] = createSignal
+ 1}>
+
+
+ {(a: Author) => (
+
-
-
-
- {t('Authors')}
+
+
+ )}
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {props.article.stat?.viewed}
-
-
-
- {props.article.stat?.commented || ''}
-
-
-
- }
- />
-
-
-
-
-
-
-
-
+
- {formattedDate()}
-
-
-
-
-
-
-
-
-
-
-
-
- {(topic) => (
-
-
-
-
- {topic.title}
-
- )}
-
- 1}>
-
-
- {(a: Author) => (
-
-
- {t('Authors')}
-
-
-
- )}
- {props.title}
-
-
{props.children}
-