Merge remote-tracking branch 'gitlab/dev' into minor-fixes
This commit is contained in:
commit
20ecc28ad9
|
@ -89,11 +89,15 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<div class="shout wide-container">
|
<div class="shout wide-container">
|
||||||
<article class="col-md-6 shift-content">
|
<article class="col-md-6 shift-content">
|
||||||
<div class={styles.shoutHeader}>
|
<div class={styles.shoutHeader}>
|
||||||
<div class={styles.shoutTopic}>
|
<div class={styles.shoutTopic}>
|
||||||
<a href={`/topic/${props.article.mainTopic}`} class={styles.mainTopicLink}>
|
<a
|
||||||
|
href={getPagePath(router, 'topic', { slug: props.article.mainTopic })}
|
||||||
|
class={styles.mainTopicLink}
|
||||||
|
>
|
||||||
{mainTopic().title}
|
{mainTopic().title}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -113,24 +117,13 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
<div class={styles.shoutCover} style={{ 'background-image': `url('${props.article.cover}')` }} />
|
<div
|
||||||
|
class={styles.shoutCover}
|
||||||
|
style={{ 'background-image': `url('${props.article.cover}')` }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show
|
<Show when={media() && props.article.layout !== 'image'}>
|
||||||
when={media() && props.article.layout !== 'image'}
|
|
||||||
fallback={
|
|
||||||
<Slider>
|
|
||||||
<For each={media() || []}>
|
|
||||||
{(m: MediaItem) => (
|
|
||||||
<>
|
|
||||||
<img src={m.url || m.pic} alt={m.title} />
|
|
||||||
<div innerHTML={m.body} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</Slider>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div class="media-items">
|
<div class="media-items">
|
||||||
<For each={media() || []}>
|
<For each={media() || []}>
|
||||||
{(m: MediaItem) => (
|
{(m: MediaItem) => (
|
||||||
|
@ -152,7 +145,25 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</article>
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={media() && props.article.layout === 'image'}>
|
||||||
|
<Slider slidesPerView={1} isPageGallery={true} isCardsWithCover={true} hasThumbs={true}>
|
||||||
|
<For each={media() || []}>
|
||||||
|
{(m: MediaItem) => (
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<div class="swiper-slide__inner">
|
||||||
|
<img src={m.url || m.pic} alt={m.title} loading="lazy" />
|
||||||
|
<div class="swiper-lazy-preloader swiper-lazy-preloader-white" />
|
||||||
|
<div class="image-description" innerHTML={m.title} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</Slider>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<div class="shout wide-container">
|
||||||
<div class="col-md-8 shift-content">
|
<div class="col-md-8 shift-content">
|
||||||
<div class={styles.shoutStats}>
|
<div class={styles.shoutStats}>
|
||||||
<div class={styles.shoutStatsItem}>
|
<div class={styles.shoutStatsItem}>
|
||||||
|
@ -237,5 +248,6 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
.swiper-slide {
|
.swiper-slide {
|
||||||
min-height: 0 !important;
|
min-height: 0 !important;
|
||||||
margin-bottom: 0 !important;
|
|
||||||
|
|
||||||
.cards-with-cover & {
|
.cards-with-cover & {
|
||||||
height: 0 !important;
|
height: 0 !important;
|
||||||
|
@ -13,6 +12,16 @@
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
padding-top: 35% !important;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,40 +1,46 @@
|
||||||
import { Swiper, Navigation, Pagination } from 'swiper'
|
import { Swiper, Navigation, Pagination, Lazy, Thumbs } from 'swiper'
|
||||||
import type { SwiperOptions } from 'swiper'
|
import type { SwiperOptions } from 'swiper'
|
||||||
import 'swiper/scss'
|
import 'swiper/scss'
|
||||||
import 'swiper/scss/navigation'
|
import 'swiper/scss/navigation'
|
||||||
import 'swiper/scss/pagination'
|
import 'swiper/scss/pagination'
|
||||||
|
import 'swiper/scss/lazy'
|
||||||
|
import 'swiper/scss/thumbs'
|
||||||
import './Slider.scss'
|
import './Slider.scss'
|
||||||
import { createEffect, createSignal, JSX } from 'solid-js'
|
import { createEffect, createSignal, JSX, Show } from 'solid-js'
|
||||||
import { Icon } from './Icon'
|
import { Icon } from './Icon'
|
||||||
|
import { clsx } from 'clsx'
|
||||||
|
|
||||||
interface SliderProps {
|
interface SliderProps {
|
||||||
title?: string
|
title?: string
|
||||||
slidesPerView?: number
|
slidesPerView?: number
|
||||||
isCardsWithCover?: boolean
|
isCardsWithCover?: boolean
|
||||||
children?: JSX.Element
|
children?: JSX.Element
|
||||||
|
class?: string
|
||||||
|
isPageGallery?: boolean
|
||||||
|
hasThumbs?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (props: SliderProps) => {
|
export default (props: SliderProps) => {
|
||||||
let el: HTMLDivElement | undefined
|
let el: HTMLDivElement | undefined
|
||||||
|
let thumbsEl: HTMLDivElement | undefined
|
||||||
let pagEl: HTMLDivElement | undefined
|
let pagEl: HTMLDivElement | undefined
|
||||||
let nextEl: HTMLDivElement | undefined
|
let nextEl: HTMLDivElement | undefined
|
||||||
let prevEl: HTMLDivElement | undefined
|
let prevEl: HTMLDivElement | undefined
|
||||||
|
|
||||||
const isCardsWithCover = typeof props.isCardsWithCover === 'boolean' ? props.isCardsWithCover : true
|
const isCardsWithCover = typeof props.isCardsWithCover === 'boolean' ? props.isCardsWithCover : true
|
||||||
|
|
||||||
|
const [swiper, setSwiper] = createSignal<Swiper>()
|
||||||
|
const [swiperThumbs, setSwiperThumbs] = createSignal<Swiper>()
|
||||||
|
|
||||||
const opts: SwiperOptions = {
|
const opts: SwiperOptions = {
|
||||||
|
lazy: true,
|
||||||
roundLengths: true,
|
roundLengths: true,
|
||||||
loop: true,
|
loop: true,
|
||||||
centeredSlides: true,
|
centeredSlides: true,
|
||||||
slidesPerView: 1,
|
slidesPerView: 1,
|
||||||
modules: [Navigation, Pagination],
|
modules: [Navigation, Pagination, Lazy, Thumbs],
|
||||||
speed: 500,
|
speed: 500,
|
||||||
navigation: { nextEl, prevEl },
|
navigation: { nextEl, prevEl },
|
||||||
pagination: {
|
|
||||||
el: pagEl,
|
|
||||||
type: 'bullets',
|
|
||||||
clickable: true
|
|
||||||
},
|
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
768: {
|
768: {
|
||||||
slidesPerView: props.slidesPerView > 0 ? props.slidesPerView : 1.66666,
|
slidesPerView: props.slidesPerView > 0 ? props.slidesPerView : 1.66666,
|
||||||
|
@ -44,13 +50,48 @@ export default (props: SliderProps) => {
|
||||||
slidesPerView: props.slidesPerView > 0 ? props.slidesPerView : 1.66666,
|
slidesPerView: props.slidesPerView > 0 ? props.slidesPerView : 1.66666,
|
||||||
spaceBetween: isCardsWithCover ? 8 : 52
|
spaceBetween: isCardsWithCover ? 8 : 52
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
thumbs: {
|
||||||
|
swiper: swiperThumbs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [swiper, setSwiper] = createSignal<Swiper>()
|
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(() => {
|
createEffect(() => {
|
||||||
if (!swiper() && !!el) {
|
if (!swiper() && !!el) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
if (swiperThumbs()) {
|
||||||
|
opts.thumbs = {
|
||||||
|
swiper: swiperThumbs()
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.pagination = {
|
||||||
|
el: '.swiper-pagination',
|
||||||
|
type: 'fraction'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setSwiper(new Swiper(el, opts))
|
setSwiper(new Swiper(el, opts))
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +102,16 @@ export default (props: SliderProps) => {
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h2 class="col-12">{props.title}</h2>
|
<h2 class="col-12">{props.title}</h2>
|
||||||
<div class="swiper" classList={{ 'cards-with-cover': isCardsWithCover }} ref={el}>
|
|
||||||
|
<div class="sliders-container">
|
||||||
|
<div
|
||||||
|
class={clsx('swiper', props.class)}
|
||||||
|
classList={{
|
||||||
|
'cards-with-cover': isCardsWithCover,
|
||||||
|
'swiper--page-gallery': props.isPageGallery
|
||||||
|
}}
|
||||||
|
ref={el}
|
||||||
|
>
|
||||||
<div class="swiper-wrapper">{props.children}</div>
|
<div class="swiper-wrapper">{props.children}</div>
|
||||||
<div class="slider-arrow-next" ref={nextEl} onClick={() => swiper()?.slideNext()}>
|
<div class="slider-arrow-next" ref={nextEl} onClick={() => swiper()?.slideNext()}>
|
||||||
<Icon name="slider-arrow" class={'icon'} />
|
<Icon name="slider-arrow" class={'icon'} />
|
||||||
|
@ -69,7 +119,16 @@ export default (props: SliderProps) => {
|
||||||
<div class="slider-arrow-prev" ref={prevEl} onClick={() => swiper()?.slidePrev()}>
|
<div class="slider-arrow-prev" ref={prevEl} onClick={() => swiper()?.slidePrev()}>
|
||||||
<Icon name="slider-arrow" class={'icon'} />
|
<Icon name="slider-arrow" class={'icon'} />
|
||||||
</div>
|
</div>
|
||||||
<div class="slider-pagination" ref={pagEl} />
|
<div class="swiper-pagination" ref={pagEl} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={props.hasThumbs}>
|
||||||
|
<div class="thumbs-container">
|
||||||
|
<div class="swiper swiper--thumbs" ref={thumbsEl}>
|
||||||
|
<div class="swiper-wrapper">{props.children}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user