parent
f1e68f219c
commit
891b9ec5f7
|
@ -20,7 +20,7 @@ import { AudioHeader } from './AudioHeader'
|
||||||
import { Popover } from '../_shared/Popover'
|
import { Popover } from '../_shared/Popover'
|
||||||
import { VideoPlayer } from '../_shared/VideoPlayer'
|
import { VideoPlayer } from '../_shared/VideoPlayer'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
import { SolidSwiper } from '../_shared/SolidSwiper'
|
import { ImageSwiper } from '../_shared/SolidSwiper'
|
||||||
import styles from './Article.module.scss'
|
import styles from './Article.module.scss'
|
||||||
import { CardTopic } from '../Feed/CardTopic'
|
import { CardTopic } from '../Feed/CardTopic'
|
||||||
import { createPopper } from '@popperjs/core'
|
import { createPopper } from '@popperjs/core'
|
||||||
|
@ -331,7 +331,7 @@ export const FullArticle = (props: Props) => {
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-20 offset-md-2">
|
<div class="col-md-20 offset-md-2">
|
||||||
<SolidSwiper images={media()} />
|
<ImageSwiper images={media()} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { GrowingTextarea } from '../_shared/GrowingTextarea'
|
||||||
import { VideoUploader } from '../Editor/VideoUploader'
|
import { VideoUploader } from '../Editor/VideoUploader'
|
||||||
import { AudioUploader } from '../Editor/AudioUploader'
|
import { AudioUploader } from '../Editor/AudioUploader'
|
||||||
import { slugify } from '../../utils/slugify'
|
import { slugify } from '../../utils/slugify'
|
||||||
import { SolidSwiper } from '../_shared/SolidSwiper'
|
import { ImageSwiper } from '../_shared/SolidSwiper'
|
||||||
import { DropArea } from '../_shared/DropArea'
|
import { DropArea } from '../_shared/DropArea'
|
||||||
import { LayoutType, MediaItem } from '../../pages/types'
|
import { LayoutType, MediaItem } from '../../pages/types'
|
||||||
import { clone } from '../../utils/clone'
|
import { clone } from '../../utils/clone'
|
||||||
|
@ -384,7 +384,7 @@ export const EditView = (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show when={props.shout.layout === 'image'}>
|
<Show when={props.shout.layout === 'image'}>
|
||||||
<SolidSwiper
|
<ImageSwiper
|
||||||
editorMode={true}
|
editorMode={true}
|
||||||
images={mediaItems()}
|
images={mediaItems()}
|
||||||
onImageChange={handleMediaChange}
|
onImageChange={handleMediaChange}
|
||||||
|
|
|
@ -8,10 +8,8 @@ import { Row1 } from '../Feed/Row1'
|
||||||
import Hero from '../Discours/Hero'
|
import Hero from '../Discours/Hero'
|
||||||
import { Beside } from '../Feed/Beside'
|
import { Beside } from '../Feed/Beside'
|
||||||
import RowShort from '../Feed/RowShort'
|
import RowShort from '../Feed/RowShort'
|
||||||
import { Slider } from '../_shared/Slider'
|
|
||||||
import Group from '../Feed/Group'
|
import Group from '../Feed/Group'
|
||||||
import type { Shout } from '../../graphql/types.gen'
|
import type { Shout } from '../../graphql/types.gen'
|
||||||
|
|
||||||
import { useTopicsStore } from '../../stores/zine/topics'
|
import { useTopicsStore } from '../../stores/zine/topics'
|
||||||
import {
|
import {
|
||||||
loadShouts,
|
loadShouts,
|
||||||
|
@ -22,8 +20,8 @@ import {
|
||||||
import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
|
import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
|
||||||
import { splitToPages } from '../../utils/splitToPages'
|
import { splitToPages } from '../../utils/splitToPages'
|
||||||
import { ArticleCard } from '../Feed/ArticleCard'
|
|
||||||
import { useLocalize } from '../../context/localize'
|
import { useLocalize } from '../../context/localize'
|
||||||
|
import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
shouts: Shout[]
|
shouts: Shout[]
|
||||||
|
@ -130,21 +128,7 @@ export const HomeView = (props: Props) => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Show when={topMonthArticles()}>
|
<Show when={topMonthArticles()}>
|
||||||
<Slider title={t('Top month articles')}>
|
<ArticleCardSwiper title={t('Top month articles')} slides={topMonthArticles()} />
|
||||||
<For each={topMonthArticles()}>
|
|
||||||
{(a) => (
|
|
||||||
<ArticleCard
|
|
||||||
article={a}
|
|
||||||
settings={{
|
|
||||||
additionalClass: 'swiper-slide',
|
|
||||||
isFloorImportant: true,
|
|
||||||
isWithCover: true,
|
|
||||||
nodate: true
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</Slider>
|
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Row2 articles={sortedArticles().slice(10, 12)} nodate={true} />
|
<Row2 articles={sortedArticles().slice(10, 12)} nodate={true} />
|
||||||
|
@ -162,21 +146,7 @@ export const HomeView = (props: Props) => {
|
||||||
{randomLayout()}
|
{randomLayout()}
|
||||||
|
|
||||||
<Show when={topArticles()}>
|
<Show when={topArticles()}>
|
||||||
<Slider title={t('Favorite')}>
|
<ArticleCardSwiper title={t('Favorite')} slides={topArticles()} />
|
||||||
<For each={topArticles()}>
|
|
||||||
{(a: Shout) => (
|
|
||||||
<ArticleCard
|
|
||||||
article={a}
|
|
||||||
settings={{
|
|
||||||
additionalClass: 'swiper-slide',
|
|
||||||
isFloorImportant: true,
|
|
||||||
isWithCover: true,
|
|
||||||
nodate: true
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</Slider>
|
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Beside
|
<Beside
|
||||||
|
|
0
src/components/Views/Topic.module.scss
Normal file
0
src/components/Views/Topic.module.scss
Normal file
|
@ -13,10 +13,10 @@ import { useAuthorsStore } from '../../stores/zine/authors'
|
||||||
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
|
import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll'
|
||||||
import { splitToPages } from '../../utils/splitToPages'
|
import { splitToPages } from '../../utils/splitToPages'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Slider } from '../_shared/Slider'
|
|
||||||
import { Row1 } from '../Feed/Row1'
|
import { Row1 } from '../Feed/Row1'
|
||||||
import { ArticleCard } from '../Feed/ArticleCard'
|
import { ArticleCard } from '../Feed/ArticleCard'
|
||||||
import { useLocalize } from '../../context/localize'
|
import { useLocalize } from '../../context/localize'
|
||||||
|
import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper'
|
||||||
|
|
||||||
type TopicsPageSearchParams = {
|
type TopicsPageSearchParams = {
|
||||||
by: 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'commented'
|
by: 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'commented'
|
||||||
|
@ -136,21 +136,7 @@ export const TopicView = (props: TopicProps) => {
|
||||||
wrapper={'author'}
|
wrapper={'author'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Slider title={title()}>
|
<ArticleCardSwiper title={title()} slides={sortedArticles().slice(5, 11)} />
|
||||||
<For each={sortedArticles().slice(5, 11)}>
|
|
||||||
{(a: Shout) => (
|
|
||||||
<ArticleCard
|
|
||||||
article={a}
|
|
||||||
settings={{
|
|
||||||
additionalClass: 'swiper-slide',
|
|
||||||
isFloorImportant: true,
|
|
||||||
isWithCover: true,
|
|
||||||
nodate: true
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</Slider>
|
|
||||||
|
|
||||||
<Beside
|
<Beside
|
||||||
beside={sortedArticles()[12]}
|
beside={sortedArticles()[12]}
|
||||||
|
@ -163,22 +149,7 @@ export const TopicView = (props: TopicProps) => {
|
||||||
<Row1 article={sortedArticles()[15]} />
|
<Row1 article={sortedArticles()[15]} />
|
||||||
|
|
||||||
<Show when={sortedArticles().length > 15}>
|
<Show when={sortedArticles().length > 15}>
|
||||||
<Slider slidesPerView={3}>
|
<ArticleCardSwiper slides={sortedArticles().slice(16, 22)} />
|
||||||
<For each={sortedArticles().slice(16, 22)}>
|
|
||||||
{(a: Shout) => (
|
|
||||||
<ArticleCard
|
|
||||||
article={a}
|
|
||||||
settings={{
|
|
||||||
additionalClass: 'swiper-slide',
|
|
||||||
isFloorImportant: true,
|
|
||||||
isWithCover: false,
|
|
||||||
nodate: true
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</Slider>
|
|
||||||
|
|
||||||
<Row3 articles={sortedArticles().slice(23, 26)} />
|
<Row3 articles={sortedArticles().slice(23, 26)} />
|
||||||
<Row2 articles={sortedArticles().slice(26, 28)} />
|
<Row2 articles={sortedArticles().slice(26, 28)} />
|
||||||
</Show>
|
</Show>
|
||||||
|
|
|
@ -1,253 +0,0 @@
|
||||||
.swiper-slide {
|
|
||||||
min-height: 0 !important;
|
|
||||||
|
|
||||||
.cards-with-cover & {
|
|
||||||
height: 0 !important;
|
|
||||||
padding-top: 100%;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
|
||||||
padding-top: 56.2% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider-arrow-prev,
|
|
||||||
.slider-arrow-next {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
outline: none;
|
|
||||||
border: 0;
|
|
||||||
transform: translate(0);
|
|
||||||
top: 0;
|
|
||||||
width: 21%;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
width: 8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.icon {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
height: 36px;
|
|
||||||
opacity: 1;
|
|
||||||
transition: opacity 0.2s;
|
|
||||||
width: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider-arrow-prev {
|
|
||||||
background: linear-gradient(to left, rgb(0 0 0 / 0%) 0%, rgb(0 0 0 / 90%) 100%);
|
|
||||||
justify-content: flex-start;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
margin-left: 5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-left: 5rem;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
margin-left: 25%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider-arrow-next {
|
|
||||||
background: linear-gradient(to left, rgb(0 0 0 / 90%) 0%, rgb(0 0 0 / 0%) 100%);
|
|
||||||
justify-content: flex-end;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
margin-right: 5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-right: 5rem;
|
|
||||||
transform: rotate(180deg);
|
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
margin-right: 25%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.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 / 20%);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uploadPreview {
|
|
||||||
background: unset;
|
|
||||||
position: relative;
|
|
||||||
padding: 0 40px;
|
|
||||||
|
|
||||||
.sliders-container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.swiper {
|
|
||||||
background: unset;
|
|
||||||
|
|
||||||
.swiper-wrapper {
|
|
||||||
min-height: 400px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider-arrow-next,
|
|
||||||
.slider-arrow-prev {
|
|
||||||
background: none;
|
|
||||||
filter: invert(1);
|
|
||||||
width: 40px;
|
|
||||||
max-height: 540px;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin: auto;
|
|
||||||
width: 12px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
//.slider-arrow-prev {
|
|
||||||
// margin-left: -40px;
|
|
||||||
//}
|
|
||||||
//.slider-arrow-next {
|
|
||||||
// margin-right: -40px;
|
|
||||||
//}
|
|
||||||
}
|
|
|
@ -1,157 +0,0 @@
|
||||||
//TODO: Replace with SolidSwiper.tsx
|
|
||||||
|
|
||||||
import { Swiper, Navigation, Pagination, Thumbs } from 'swiper'
|
|
||||||
import type { SwiperOptions } from 'swiper'
|
|
||||||
import 'swiper/scss'
|
|
||||||
import 'swiper/scss/navigation'
|
|
||||||
import 'swiper/scss/pagination'
|
|
||||||
import 'swiper/scss/thumbs'
|
|
||||||
import './Slider.scss'
|
|
||||||
import { createEffect, createSignal, JSX, on, Show } from 'solid-js'
|
|
||||||
import { Icon } from '../Icon'
|
|
||||||
import { clsx } from 'clsx'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
title?: string
|
|
||||||
slidesPerView?: number
|
|
||||||
isCardsWithCover?: boolean
|
|
||||||
children?: JSX.Element
|
|
||||||
isPageGallery?: boolean
|
|
||||||
hasThumbs?: boolean
|
|
||||||
variant?: 'uploadPreview'
|
|
||||||
slideIndex?: (value: number) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Slider = (props: Props) => {
|
|
||||||
let el: HTMLDivElement | undefined
|
|
||||||
let thumbsEl: HTMLDivElement | undefined
|
|
||||||
let nextEl: HTMLDivElement | undefined
|
|
||||||
let prevEl: HTMLDivElement | undefined
|
|
||||||
|
|
||||||
const isCardsWithCover = typeof props.isCardsWithCover === 'boolean' ? props.isCardsWithCover : true
|
|
||||||
|
|
||||||
const [swiper, setSwiper] = createSignal<Swiper>()
|
|
||||||
const [swiperThumbs, setSwiperThumbs] = createSignal<Swiper>()
|
|
||||||
const opts: SwiperOptions = {
|
|
||||||
observer: true,
|
|
||||||
observeParents: true,
|
|
||||||
roundLengths: true,
|
|
||||||
loop: true,
|
|
||||||
centeredSlides: true,
|
|
||||||
slidesPerView: 1,
|
|
||||||
modules: [Navigation, Pagination, Thumbs],
|
|
||||||
speed: 500,
|
|
||||||
on: {
|
|
||||||
slideChange: () => {
|
|
||||||
if (swiper()) {
|
|
||||||
props.slideIndex(swiper().realIndex || 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
navigation: { nextEl, prevEl },
|
|
||||||
breakpoints: {
|
|
||||||
768: {
|
|
||||||
slidesPerView: props.slidesPerView > 0 ? props.slidesPerView : 1.66666,
|
|
||||||
spaceBetween: isCardsWithCover ? 8 : 26
|
|
||||||
},
|
|
||||||
992: {
|
|
||||||
slidesPerView: props.slidesPerView > 0 ? props.slidesPerView : 1.66666,
|
|
||||||
spaceBetween: isCardsWithCover ? 8 : 52
|
|
||||||
}
|
|
||||||
},
|
|
||||||
thumbs: {
|
|
||||||
swiper: swiperThumbs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
if (props.hasThumbs && !!thumbsEl) {
|
|
||||||
setSwiperThumbs(
|
|
||||||
new Swiper(thumbsEl, {
|
|
||||||
slidesPerView: 'auto',
|
|
||||||
modules: [Thumbs],
|
|
||||||
roundLengths: true,
|
|
||||||
spaceBetween: 20,
|
|
||||||
freeMode: true,
|
|
||||||
breakpoints: {
|
|
||||||
768: {
|
|
||||||
direction: 'vertical'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
if (!swiper() && !!el) {
|
|
||||||
if (swiperThumbs()) {
|
|
||||||
opts.thumbs = {
|
|
||||||
swiper: swiperThumbs()
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.pagination = {
|
|
||||||
el: '.swiper-pagination',
|
|
||||||
type: 'fraction'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setSwiper(new Swiper(el, opts))
|
|
||||||
swiper().update()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
swiper().update()
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class={clsx('floor', 'floor--important', props.variant)}>
|
|
||||||
<div class="wide-container">
|
|
||||||
<div class="row">
|
|
||||||
<Show when={props.title}>
|
|
||||||
<h2 class="col-24">{props.title}</h2>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<div class="sliders-container">
|
|
||||||
<div
|
|
||||||
class={clsx('swiper')}
|
|
||||||
classList={{
|
|
||||||
'cards-with-cover': isCardsWithCover,
|
|
||||||
'swiper--page-gallery': props.isPageGallery
|
|
||||||
}}
|
|
||||||
ref={el}
|
|
||||||
>
|
|
||||||
<div class="swiper-wrapper">{props.children}</div>
|
|
||||||
<Show when={!(props.variant === 'uploadPreview')}>
|
|
||||||
<div class="slider-arrow-next" ref={nextEl} onClick={() => swiper()?.slideNext()}>
|
|
||||||
<Icon name="slider-arrow" class={'icon'} />
|
|
||||||
</div>
|
|
||||||
<div class="slider-arrow-prev" ref={prevEl} onClick={() => swiper()?.slidePrev()}>
|
|
||||||
<Icon name="slider-arrow" class={'icon'} />
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
{/*<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>
|
|
||||||
<Show when={props.variant === 'uploadPreview'}>
|
|
||||||
<div class="slider-arrow-next" ref={nextEl} onClick={() => swiper()?.slideNext()}>
|
|
||||||
<Icon name="slider-arrow" class={'icon'} />
|
|
||||||
</div>
|
|
||||||
<div class="slider-arrow-prev" ref={prevEl} onClick={() => swiper()?.slidePrev()}>
|
|
||||||
<Icon name="slider-arrow" class={'icon'} />
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { Slider } from './Slider'
|
|
97
src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx
Normal file
97
src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
import { createSignal, For, Show } from 'solid-js'
|
||||||
|
import { Icon } from '../Icon'
|
||||||
|
import { register } from 'swiper/element/bundle'
|
||||||
|
import SwiperCore, { Manipulation, Navigation, Pagination } from 'swiper'
|
||||||
|
import { SwiperRef } from './swiper'
|
||||||
|
import { clsx } from 'clsx'
|
||||||
|
import styles from './Swiper.module.scss'
|
||||||
|
import { Shout } from '../../../graphql/types.gen'
|
||||||
|
import { ArticleCard } from '../../Feed/ArticleCard'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
slides: Shout[]
|
||||||
|
slidesPerView?: number
|
||||||
|
title?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
register()
|
||||||
|
|
||||||
|
SwiperCore.use([Pagination, Navigation, Manipulation])
|
||||||
|
|
||||||
|
export const ArticleCardSwiper = (props: Props) => {
|
||||||
|
const [slideIndex, setSlideIndex] = createSignal(0)
|
||||||
|
|
||||||
|
const mainSwipeRef: { current: SwiperRef } = { current: null }
|
||||||
|
|
||||||
|
const handleSlideChange = () => {
|
||||||
|
setSlideIndex(mainSwipeRef.current.swiper.activeIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={clsx(styles.Swiper, styles.articleMode, styles.ArticleCardSwiper)}>
|
||||||
|
<Show when={props.title}>
|
||||||
|
<h2 class={styles.sliderTitle}>{props.title}</h2>
|
||||||
|
</Show>
|
||||||
|
<div class={styles.container}>
|
||||||
|
<Show when={props.slides.length > 0}>
|
||||||
|
<div class={styles.holder}>
|
||||||
|
<swiper-container
|
||||||
|
ref={(el) => (mainSwipeRef.current = el)}
|
||||||
|
centered-slides={true}
|
||||||
|
thumbs-swiper={'.thumbSwiper'}
|
||||||
|
observer={true}
|
||||||
|
onSlideChange={handleSlideChange}
|
||||||
|
slides-per-view={props.slidesPerView ?? 1.5}
|
||||||
|
space-between={52}
|
||||||
|
breakpoints={{ 768: { spaceBetween: 26 }, 992: { spaceBetween: 52 } }}
|
||||||
|
loop={true}
|
||||||
|
speed={800}
|
||||||
|
autoplay={{
|
||||||
|
disableOnInteraction: false,
|
||||||
|
delay: 3000,
|
||||||
|
pauseOnMouseEnter: true
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<For each={props.slides}>
|
||||||
|
{(slide, index) => (
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
<swiper-slide virtual-index={index()}>
|
||||||
|
<ArticleCard
|
||||||
|
article={slide}
|
||||||
|
settings={{
|
||||||
|
additionalClass: 'swiper-slide',
|
||||||
|
isFloorImportant: true,
|
||||||
|
isWithCover: true,
|
||||||
|
nodate: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</swiper-slide>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</swiper-container>
|
||||||
|
<div
|
||||||
|
class={clsx(styles.navigation, styles.prev, {
|
||||||
|
[styles.disabled]: slideIndex() === 0
|
||||||
|
})}
|
||||||
|
onClick={() => mainSwipeRef.current.swiper.slidePrev()}
|
||||||
|
>
|
||||||
|
<Icon name="swiper-l-arr" class={styles.icon} />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class={clsx(styles.navigation, styles.next, {
|
||||||
|
[styles.disabled]: slideIndex() + 1 === props.slides.length
|
||||||
|
})}
|
||||||
|
onClick={() => mainSwipeRef.current.swiper.slideNext()}
|
||||||
|
>
|
||||||
|
<Icon name="swiper-r-arr" class={styles.icon} />
|
||||||
|
</div>
|
||||||
|
<div class={styles.counter}>
|
||||||
|
{slideIndex() + 1} / {props.slides.length}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { createEffect, createSignal, For, Show, on } from 'solid-js'
|
import { createEffect, createSignal, For, Show, on, JSXElement } from 'solid-js'
|
||||||
import { MediaItem, UploadedFile } from '../../../pages/types'
|
import { MediaItem, UploadedFile } from '../../../pages/types'
|
||||||
import { Icon } from '../Icon'
|
import { Icon } from '../Icon'
|
||||||
import { Popover } from '../Popover'
|
import { Popover } from '../Popover'
|
||||||
|
@ -32,7 +32,7 @@ register()
|
||||||
|
|
||||||
SwiperCore.use([Pagination, Navigation, Manipulation])
|
SwiperCore.use([Pagination, Navigation, Manipulation])
|
||||||
|
|
||||||
export const SolidSwiper = (props: Props) => {
|
export const ImageSwiper = (props: Props) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const [loading, setLoading] = createSignal(false)
|
const [loading, setLoading] = createSignal(false)
|
||||||
const [slideIndex, setSlideIndex] = createSignal(0)
|
const [slideIndex, setSlideIndex] = createSignal(0)
|
||||||
|
@ -68,7 +68,6 @@ export const SolidSwiper = (props: Props) => {
|
||||||
{ defer: true }
|
{ defer: true }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleDropAreaUpload = (value: UploadedFile[]) => {
|
const handleDropAreaUpload = (value: UploadedFile[]) => {
|
||||||
props.onImagesAdd(composeMediaItems(value))
|
props.onImagesAdd(composeMediaItems(value))
|
||||||
swipeToUploaded()
|
swipeToUploaded()
|
|
@ -13,6 +13,17 @@ $navigation-reserve: 32px;
|
||||||
margin: 2rem 0;
|
margin: 2rem 0;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
&.ArticleCardSwiper {
|
||||||
|
margin-bottom: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliderTitle {
|
||||||
|
@include font-size(4.5rem);
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
padding: 4rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
&.articleMode {
|
&.articleMode {
|
||||||
background: var(--background-color-invert);
|
background: var(--background-color-invert);
|
||||||
color: var(--default-color-invert);
|
color: var(--default-color-invert);
|
||||||
|
@ -114,6 +125,10 @@ $navigation-reserve: 32px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: calc(100% - 130px);
|
width: calc(100% - 130px);
|
||||||
|
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.counter {
|
.counter {
|
||||||
@include font-size(1.2rem);
|
@include font-size(1.2rem);
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export { SolidSwiper } from './SolidSwiper'
|
export { ImageSwiper } from './ImageSwiper'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'solid-js'
|
import 'solid-js'
|
||||||
import { SwiperOptions } from 'swiper'
|
import { SwiperOptions, AutoplayOptions } from 'swiper'
|
||||||
import { SwiperSlideProps } from 'swiper/react'
|
import { SwiperSlideProps } from 'swiper/react'
|
||||||
|
|
||||||
type Kebab<T extends string, A extends string = ''> = T extends `${infer F}${infer R}`
|
type Kebab<T extends string, A extends string = ''> = T extends `${infer F}${infer R}`
|
||||||
|
@ -37,6 +37,11 @@ declare module 'solid-js' {
|
||||||
onSlideChange?: () => void
|
onSlideChange?: () => void
|
||||||
onBeforeSlideChangeStart?: () => void
|
onBeforeSlideChangeStart?: () => void
|
||||||
class?: string
|
class?: string
|
||||||
|
breakpoints?: {
|
||||||
|
[width: number]: SwiperOptions
|
||||||
|
[ratio: string]: SwiperOptions
|
||||||
|
}
|
||||||
|
autoplay?: AutoplayOptions | boolean
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||||
interface SwiperSlideAttributes extends KebabObjectKeys<SwiperSlideProps> {
|
interface SwiperSlideAttributes extends KebabObjectKeys<SwiperSlideProps> {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user