slider-as-wrapper
This commit is contained in:
parent
7a97e8303d
commit
a3f63e0da0
|
@ -11,6 +11,7 @@ import { deleteReaction } from '../../stores/zine/reactions'
|
||||||
import { formatDate } from '../../utils'
|
import { formatDate } from '../../utils'
|
||||||
import { SharePopup } from './SharePopup'
|
import { SharePopup } from './SharePopup'
|
||||||
import stylesHeader from '../Nav/Header.module.scss'
|
import stylesHeader from '../Nav/Header.module.scss'
|
||||||
|
import Userpic from '../Author/Userpic'
|
||||||
|
|
||||||
export default (props: {
|
export default (props: {
|
||||||
level?: number
|
level?: number
|
||||||
|
@ -40,16 +41,11 @@ export default (props: {
|
||||||
<Show
|
<Show
|
||||||
when={!props.compact}
|
when={!props.compact}
|
||||||
fallback={
|
fallback={
|
||||||
<div class={styles.commentDetails}>
|
<div>
|
||||||
<a href={`/author/${comment()?.createdBy?.slug}`}>
|
<Userpic user={comment().createdBy as Author} isBig={false} isAuthorsList={false} />
|
||||||
@{(comment()?.createdBy || { name: 'anonymous' }).name}
|
<small class={styles.commentArticle}>
|
||||||
</a>
|
<a href={`#comment-${comment()?.id}`}>{comment()?.shout.title || ''}</a>
|
||||||
<div class={styles.commentArticle}>
|
</small>
|
||||||
<Icon name="reply-arrow" />
|
|
||||||
<a href={`#comment-${comment()?.id}`}>
|
|
||||||
#{(comment()?.shout || { title: 'Lorem ipsum titled' }).title}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -141,9 +137,9 @@ export default (props: {
|
||||||
<textarea name="reply" id="reply" rows="5"></textarea>
|
<textarea name="reply" id="reply" rows="5"></textarea>
|
||||||
<div class={styles.replyFormControls}>
|
<div class={styles.replyFormControls}>
|
||||||
<button class="button button--light" onClick={() => setIsReplyVisible(false)}>
|
<button class="button button--light" onClick={() => setIsReplyVisible(false)}>
|
||||||
Отмена
|
{t('Cancel')}
|
||||||
</button>
|
</button>
|
||||||
<button class="button">Отправить</button>
|
<button class="button">{t('Send')}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { clsx } from 'clsx'
|
||||||
import { CommentsTree } from './CommentsTree'
|
import { CommentsTree } from './CommentsTree'
|
||||||
import { useSession } from '../../context/session'
|
import { useSession } from '../../context/session'
|
||||||
import VideoPlayer from './VideoPlayer'
|
import VideoPlayer from './VideoPlayer'
|
||||||
|
import Slider from '../_shared/Slider'
|
||||||
|
|
||||||
interface ArticleProps {
|
interface ArticleProps {
|
||||||
article: Shout
|
article: Shout
|
||||||
|
@ -29,13 +30,7 @@ interface MediaItem {
|
||||||
const MediaView = (props: { media: MediaItem; kind: Shout['layout'] }) => {
|
const MediaView = (props: { media: MediaItem; kind: Shout['layout'] }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Switch
|
<Switch fallback={<a href={props.media.url}>{t('Cannot show this media type')}</a>}>
|
||||||
fallback={
|
|
||||||
<picture>
|
|
||||||
<source src={props.media.url} />
|
|
||||||
</picture>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Match when={props.kind === 'audio'}>
|
<Match when={props.kind === 'audio'}>
|
||||||
<div>
|
<div>
|
||||||
<h5>{props.media.title}</h5>
|
<h5>{props.media.title}</h5>
|
||||||
|
@ -116,7 +111,21 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
<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 when={media()}>
|
<Show
|
||||||
|
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) => (
|
||||||
|
@ -148,7 +157,7 @@ export const FullArticle = (props: ArticleProps) => {
|
||||||
<Show when={props.article.stat?.viewed}>
|
<Show when={props.article.stat?.viewed}>
|
||||||
<div class={clsx(styles.shoutStatsItem)}>
|
<div class={clsx(styles.shoutStatsItem)}>
|
||||||
<Icon name="eye" class={styles.icon} />
|
<Icon name="eye" class={styles.icon} />
|
||||||
<sup>{props.article.stat?.viewed}</sup>
|
{props.article.stat?.viewed}
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,6 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
||||||
() => session()?.news?.authors?.some((u) => u === props.author.slug) || false
|
() => session()?.news?.authors?.some((u) => u === props.author.slug) || false
|
||||||
)
|
)
|
||||||
const canFollow = createMemo(() => !props.hideFollow && session()?.user?.slug !== props.author.slug)
|
const canFollow = createMemo(() => !props.hideFollow && session()?.user?.slug !== props.author.slug)
|
||||||
const bio = createMemo(() => {
|
|
||||||
return props.caption || props.author.bio || t('Our regular contributor')
|
|
||||||
})
|
|
||||||
|
|
||||||
const name = () => {
|
const name = () => {
|
||||||
return props.author.name === 'Дискурс' && locale() !== 'ru'
|
return props.author.name === 'Дискурс' && locale() !== 'ru'
|
||||||
|
@ -76,7 +73,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
||||||
<div
|
<div
|
||||||
class={styles.authorAbout}
|
class={styles.authorAbout}
|
||||||
classList={{ 'text-truncate': props.truncateBio }}
|
classList={{ 'text-truncate': props.truncateBio }}
|
||||||
innerHTML={props.caption || bio()}
|
innerHTML={props.author.bio}
|
||||||
></div>
|
></div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -51,6 +51,7 @@ export default (props: UserpicProps) => {
|
||||||
src={props.user.userpic || '/icons/user-default.svg'}
|
src={props.user.userpic || '/icons/user-default.svg'}
|
||||||
alt={props.user.name || ''}
|
alt={props.user.name || ''}
|
||||||
classList={{ anonymous: !props.user.userpic }}
|
classList={{ anonymous: !props.user.userpic }}
|
||||||
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
a {
|
a {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
height: 1.2em;
|
||||||
|
width: 1.2em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutCardWithBorder {
|
.shoutCardWithBorder {
|
||||||
|
|
|
@ -13,9 +13,10 @@ import { t } from '../../utils/intl'
|
||||||
import { Row3 } from '../Feed/Row3'
|
import { Row3 } from '../Feed/Row3'
|
||||||
import { Row2 } from '../Feed/Row2'
|
import { Row2 } from '../Feed/Row2'
|
||||||
import { Beside } from '../Feed/Beside'
|
import { Beside } from '../Feed/Beside'
|
||||||
import Slider from '../Feed/Slider'
|
import Slider from '../_shared/Slider'
|
||||||
import { Row1 } from '../Feed/Row1'
|
import { Row1 } from '../Feed/Row1'
|
||||||
import styles from '../../styles/Topic.module.scss'
|
import styles from '../../styles/Topic.module.scss'
|
||||||
|
import { ArticleCard } from '../Feed/Card'
|
||||||
|
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 21
|
export const PRERENDERED_ARTICLES_COUNT = 21
|
||||||
const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
|
const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
|
||||||
|
@ -106,7 +107,21 @@ export const LayoutShoutsPage = (props: PageProps) => {
|
||||||
<ModeSwitcher />
|
<ModeSwitcher />
|
||||||
<Row1 article={sortedArticles()[0]} />
|
<Row1 article={sortedArticles()[0]} />
|
||||||
<Row2 articles={sortedArticles().slice(1, 3)} />
|
<Row2 articles={sortedArticles().slice(1, 3)} />
|
||||||
<Slider title={title()} articles={sortedArticles().slice(5, 11)} />
|
<Slider title={title()}>
|
||||||
|
<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]}
|
||||||
title={t('Top viewed')}
|
title={t('Top viewed')}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { createEffect, createMemo, createSignal, For, onMount, Show } from 'solid-js'
|
import { createEffect, createMemo, createSignal, For, onMount, Show } from 'solid-js'
|
||||||
import type { Author } from '../../graphql/types.gen'
|
import type { Author } from '../../graphql/types.gen'
|
||||||
import { AuthorCard } from '../Author/Card'
|
|
||||||
import { t } from '../../utils/intl'
|
import { t } from '../../utils/intl'
|
||||||
import { useAuthorsStore, setAuthorsSort } from '../../stores/zine/authors'
|
import { AuthorsSortBy, setAuthorsSort, useAuthorsStore } from '../../stores/zine/authors'
|
||||||
import { useRouter } from '../../stores/router'
|
import { useRouter } from '../../stores/router'
|
||||||
import styles from '../../styles/AllTopics.module.scss'
|
import { AuthorCard } from '../Author/Card'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { useSession } from '../../context/session'
|
import { useSession } from '../../context/session'
|
||||||
import { locale } from '../../stores/ui'
|
import { locale } from '../../stores/ui'
|
||||||
import { translit } from '../../utils/ru2en'
|
import { translit } from '../../utils/ru2en'
|
||||||
|
import styles from '../../styles/AllTopics.module.scss'
|
||||||
import { SearchField } from '../_shared/SearchField'
|
import { SearchField } from '../_shared/SearchField'
|
||||||
import { scrollHandler } from '../../utils/scroll'
|
import { scrollHandler } from '../../utils/scroll'
|
||||||
import { StatMetrics } from '../_shared/StatMetrics'
|
import { StatMetrics } from '../_shared/StatMetrics'
|
||||||
|
@ -17,19 +17,20 @@ type AllAuthorsPageSearchParams = {
|
||||||
by: '' | 'name' | 'shouts' | 'followers'
|
by: '' | 'name' | 'shouts' | 'followers'
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = {
|
type AllAuthorsViewProps = {
|
||||||
authors: Author[]
|
authors: Author[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const PAGE_SIZE = 20
|
const PAGE_SIZE = 20
|
||||||
const ALPHABET = [...'@АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ']
|
const ALPHABET = [...'@АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ']
|
||||||
|
|
||||||
export const AllAuthorsView = (props: Props) => {
|
export const AllAuthorsView = (props: AllAuthorsViewProps) => {
|
||||||
const [limit, setLimit] = createSignal(PAGE_SIZE)
|
const [limit, setLimit] = createSignal(PAGE_SIZE)
|
||||||
const { searchParams, changeSearchParam } = useRouter<AllAuthorsPageSearchParams>()
|
const { searchParams, changeSearchParam } = useRouter()
|
||||||
|
const [filterResults, setFilterResults] = createSignal<Author[]>([])
|
||||||
const { sortedAuthors } = useAuthorsStore({
|
const { sortedAuthors } = useAuthorsStore({
|
||||||
authors: props.authors,
|
authors: props.authors,
|
||||||
sortBy: searchParams().by || 'name'
|
sortBy: (searchParams().by || 'shouts') as AuthorsSortBy
|
||||||
})
|
})
|
||||||
|
|
||||||
const { session } = useSession()
|
const { session } = useSession()
|
||||||
|
@ -41,13 +42,11 @@ export const AllAuthorsView = (props: Props) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
setAuthorsSort(searchParams().by || 'shouts')
|
setAuthorsSort((searchParams().by || 'shouts') as AuthorsSortBy)
|
||||||
setFilteredAuthors(sortedAuthors())
|
setFilterResults(sortedAuthors())
|
||||||
setLimit(PAGE_SIZE)
|
setLimit(PAGE_SIZE)
|
||||||
})
|
})
|
||||||
|
|
||||||
const subscribed = (s) => Boolean(session()?.news?.authors && session()?.news?.authors?.includes(s || ''))
|
|
||||||
|
|
||||||
const byLetter = createMemo<{ [letter: string]: Author[] }>(() => {
|
const byLetter = createMemo<{ [letter: string]: Author[] }>(() => {
|
||||||
return sortedAuthors().reduce((acc, author) => {
|
return sortedAuthors().reduce((acc, author) => {
|
||||||
let letter = author.name.trim().split(' ').pop().at(0).toUpperCase()
|
let letter = author.name.trim().split(' ').pop().at(0).toUpperCase()
|
||||||
|
@ -64,6 +63,39 @@ export const AllAuthorsView = (props: Props) => {
|
||||||
return keys
|
return keys
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const subscribed = (s) => Boolean(session()?.news?.authors && session()?.news?.authors?.includes(s || ''))
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
|
const filterAuthors = (value) => {
|
||||||
|
/* very stupid filter by string algorithm with no deps */
|
||||||
|
let q = value.toLowerCase()
|
||||||
|
if (q.length > 0) {
|
||||||
|
setFilterResults([])
|
||||||
|
if (locale() === 'ru') q = translit(q, 'ru')
|
||||||
|
const aaa: Author[] = sortedAuthors()
|
||||||
|
sortedAuthors().forEach((author) => {
|
||||||
|
let flag = false
|
||||||
|
author.slug.split('-').forEach((w) => {
|
||||||
|
if (w.startsWith(q)) flag = true
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!flag) {
|
||||||
|
let wrds: string = author.name.toLowerCase()
|
||||||
|
if (locale() === 'ru') wrds = translit(wrds, 'ru')
|
||||||
|
wrds.split(' ').forEach((w: string) => {
|
||||||
|
if (w.startsWith(q)) flag = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!flag && aaa.includes(author)) {
|
||||||
|
const idx = aaa.indexOf(author)
|
||||||
|
aaa.splice(idx, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setFilterResults(aaa)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const showMore = () => setLimit((oldLimit) => oldLimit + PAGE_SIZE)
|
const showMore = () => setLimit((oldLimit) => oldLimit + PAGE_SIZE)
|
||||||
const AllAuthorsHead = () => (
|
const AllAuthorsHead = () => (
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -76,54 +108,24 @@ export const AllAuthorsView = (props: Props) => {
|
||||||
<a href="/authors?by=shouts">{t('By shouts')}</a>
|
<a href="/authors?by=shouts">{t('By shouts')}</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: searchParams().by === 'followers' }}>
|
<li classList={{ selected: searchParams().by === 'followers' }}>
|
||||||
<a href="/authors?by=followers">{t('By rating')}</a>
|
<a href="/authors?by=followers">{t('By popularity')}</a>
|
||||||
</li>
|
</li>
|
||||||
<li classList={{ selected: !searchParams().by || searchParams().by === 'name' }}>
|
<li classList={{ selected: searchParams().by === 'name' }}>
|
||||||
<a href="/authors?by=name">{t('By name')}</a>
|
<a href="/authors?by=name">{t('By name')}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="view-switcher__search">
|
<Show when={searchParams().by !== 'name'}>
|
||||||
<li class="view-switcher__search">
|
<li class="view-switcher__search">
|
||||||
<SearchField onChange={filterAuthors} />
|
<SearchField onChange={filterAuthors} />
|
||||||
</li>
|
</li>
|
||||||
</li>
|
</Show>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
const [filteredAuthors, setFilteredAuthors] = createSignal<Author[]>([])
|
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
||||||
const filterAuthors = (value) => {
|
|
||||||
/* very stupid search algorithm with no deps */
|
|
||||||
let q = value.toLowerCase()
|
|
||||||
if (q.length > 0) {
|
|
||||||
setFilteredAuthors([])
|
|
||||||
if (locale() === 'ru') q = translit(q, 'ru')
|
|
||||||
const aaa: Author[] = sortedAuthors()
|
|
||||||
sortedAuthors().forEach((a) => {
|
|
||||||
let flag = false
|
|
||||||
a.slug.split('-').forEach((w) => {
|
|
||||||
if (w.startsWith(q)) flag = true
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!flag) {
|
|
||||||
let wrds: string = a.name.toLowerCase()
|
|
||||||
if (locale() === 'ru') wrds = translit(wrds, 'ru')
|
|
||||||
wrds.split(' ').forEach((w: string) => {
|
|
||||||
if (w.startsWith(q)) flag = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!flag && aaa.includes(a)) {
|
|
||||||
const idx = aaa.indexOf(a)
|
|
||||||
aaa.splice(idx, 1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
setFilteredAuthors(aaa)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div class={clsx(styles.allTopicsPage, 'wide-container')}>
|
<div class={clsx(styles.allTopicsPage, 'wide-container')}>
|
||||||
<Show when={sortedAuthors().length > 0 || filteredAuthors().length > 0}>
|
<Show when={sortedAuthors().length > 0}>
|
||||||
<div class="shift-content">
|
<div class="shift-content">
|
||||||
<AllAuthorsHead />
|
<AllAuthorsHead />
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ export const AllAuthorsView = (props: Props) => {
|
||||||
<div class="col-lg-10 col-xl-9">
|
<div class="col-lg-10 col-xl-9">
|
||||||
<ul class={clsx('nodash', styles.alphabet)}>
|
<ul class={clsx('nodash', styles.alphabet)}>
|
||||||
<For each={ALPHABET}>
|
<For each={ALPHABET}>
|
||||||
{(letter: string, index) => (
|
{(letter, index) => (
|
||||||
<li>
|
<li>
|
||||||
<Show when={letter in byLetter()} fallback={letter}>
|
<Show when={letter in byLetter()} fallback={letter}>
|
||||||
<a
|
<a
|
||||||
|
@ -176,15 +178,12 @@ export const AllAuthorsView = (props: Props) => {
|
||||||
</For>
|
</For>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={searchParams().by && searchParams().by !== 'name'}>
|
<Show when={searchParams().by && searchParams().by !== 'title'}>
|
||||||
<div class={clsx(styles.stats, 'row')}>
|
<For each={filterResults().slice(0, limit())}>
|
||||||
<div class="col-lg-10 col-xl-9">
|
|
||||||
<For each={filteredAuthors().slice(0, limit())}>
|
|
||||||
{(author) => (
|
{(author) => (
|
||||||
<>
|
<>
|
||||||
<AuthorCard
|
<AuthorCard
|
||||||
author={author}
|
author={author}
|
||||||
compact={false}
|
|
||||||
hasLink={true}
|
hasLink={true}
|
||||||
subscribed={subscribed(author.slug)}
|
subscribed={subscribed(author.slug)}
|
||||||
noSocialButtons={true}
|
noSocialButtons={true}
|
||||||
|
@ -195,8 +194,6 @@ export const AllAuthorsView = (props: Props) => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={sortedAuthors().length > limit() && searchParams().by !== 'name'}>
|
<Show when={sortedAuthors().length > limit() && searchParams().by !== 'name'}>
|
||||||
|
|
|
@ -8,7 +8,7 @@ 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 '../Feed/Slider'
|
import Slider from '../_shared/Slider'
|
||||||
import Group from '../Feed/Group'
|
import Group from '../Feed/Group'
|
||||||
import type { Shout, Topic } from '../../graphql/types.gen'
|
import type { Shout, Topic } from '../../graphql/types.gen'
|
||||||
import { t } from '../../utils/intl'
|
import { t } from '../../utils/intl'
|
||||||
|
@ -18,6 +18,7 @@ import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
|
||||||
import { locale } from '../../stores/ui'
|
import { locale } from '../../stores/ui'
|
||||||
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/Card'
|
||||||
|
|
||||||
type HomeProps = {
|
type HomeProps = {
|
||||||
randomTopics: Topic[]
|
randomTopics: Topic[]
|
||||||
|
@ -120,7 +121,21 @@ export const HomeView = (props: HomeProps) => {
|
||||||
wrapper={'author'}
|
wrapper={'author'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Slider title={t('Top month articles')} articles={topMonthArticles()} />
|
<Slider title={t('Top month articles')}>
|
||||||
|
<For each={topMonthArticles()}>
|
||||||
|
{(a: Shout) => (
|
||||||
|
<ArticleCard
|
||||||
|
article={a}
|
||||||
|
settings={{
|
||||||
|
additionalClass: 'swiper-slide',
|
||||||
|
isFloorImportant: true,
|
||||||
|
isWithCover: true,
|
||||||
|
nodate: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</Slider>
|
||||||
|
|
||||||
<Row2 articles={sortedArticles().slice(10, 12)} />
|
<Row2 articles={sortedArticles().slice(10, 12)} />
|
||||||
|
|
||||||
|
@ -132,7 +147,21 @@ export const HomeView = (props: HomeProps) => {
|
||||||
|
|
||||||
{randomLayout()}
|
{randomLayout()}
|
||||||
|
|
||||||
<Slider title={t('Favorite')} articles={topArticles()} />
|
<Slider title={t('Favorite')}>
|
||||||
|
<For each={topArticles()}>
|
||||||
|
{(a: Shout) => (
|
||||||
|
<ArticleCard
|
||||||
|
article={a}
|
||||||
|
settings={{
|
||||||
|
additionalClass: 'swiper-slide',
|
||||||
|
isFloorImportant: true,
|
||||||
|
isWithCover: true,
|
||||||
|
nodate: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</Slider>
|
||||||
|
|
||||||
<Beside
|
<Beside
|
||||||
beside={sortedArticles()[20]}
|
beside={sortedArticles()[20]}
|
||||||
|
|
|
@ -13,8 +13,9 @@ 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 '../Feed/Slider'
|
import Slider from '../_shared/Slider'
|
||||||
import { Row1 } from '../Feed/Row1'
|
import { Row1 } from '../Feed/Row1'
|
||||||
|
import { ArticleCard } from '../Feed/Card'
|
||||||
|
|
||||||
type TopicsPageSearchParams = {
|
type TopicsPageSearchParams = {
|
||||||
by: 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'commented'
|
by: 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'commented'
|
||||||
|
@ -122,7 +123,21 @@ export const TopicView = (props: TopicProps) => {
|
||||||
wrapper={'author'}
|
wrapper={'author'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Slider title={title()} articles={sortedArticles().slice(5, 11)} />
|
<Slider title={title()}>
|
||||||
|
<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]}
|
||||||
|
@ -134,12 +149,21 @@ export const TopicView = (props: TopicProps) => {
|
||||||
<Row2 articles={sortedArticles().slice(13, 15)} isEqual={true} />
|
<Row2 articles={sortedArticles().slice(13, 15)} isEqual={true} />
|
||||||
<Row1 article={sortedArticles()[15]} />
|
<Row1 article={sortedArticles()[15]} />
|
||||||
|
|
||||||
<Slider
|
<Slider slidesPerView={3} title={title()}>
|
||||||
title={title()}
|
<For each={sortedArticles().slice(16, 22)}>
|
||||||
articles={sortedArticles().slice(16, 22)}
|
{(a: Shout) => (
|
||||||
slidesPerView={3}
|
<ArticleCard
|
||||||
isCardsWithCover={false}
|
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)} />
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { ArticleCard } from './Card'
|
|
||||||
import { Swiper, Navigation, Pagination } from 'swiper'
|
import { Swiper, Navigation, Pagination } from 'swiper'
|
||||||
import type { SwiperOptions } from 'swiper'
|
import type { SwiperOptions } from 'swiper'
|
||||||
import 'swiper/scss'
|
import 'swiper/scss'
|
||||||
|
@ -6,14 +5,15 @@ import 'swiper/scss/navigation'
|
||||||
import 'swiper/scss/pagination'
|
import 'swiper/scss/pagination'
|
||||||
import './Slider.scss'
|
import './Slider.scss'
|
||||||
import type { Shout } from '../../graphql/types.gen'
|
import type { Shout } from '../../graphql/types.gen'
|
||||||
import { createEffect, createMemo, createSignal, Show, For } from 'solid-js'
|
import { createEffect, createMemo, createSignal, Show, For, JSX } from 'solid-js'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from './Icon'
|
||||||
|
|
||||||
interface SliderProps {
|
interface SliderProps {
|
||||||
title?: string
|
title?: string
|
||||||
articles: Shout[]
|
articles?: Shout[]
|
||||||
slidesPerView?: number
|
slidesPerView?: number
|
||||||
isCardsWithCover?: boolean
|
isCardsWithCover?: boolean
|
||||||
|
children?: JSX.Element
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (props: SliderProps) => {
|
export default (props: SliderProps) => {
|
||||||
|
@ -66,21 +66,7 @@ export default (props: SliderProps) => {
|
||||||
<h2 class="col-12">{props.title}</h2>
|
<h2 class="col-12">{props.title}</h2>
|
||||||
<Show when={!!articles()}>
|
<Show when={!!articles()}>
|
||||||
<div class="swiper" classList={{ 'cards-with-cover': isCardsWithCover }} ref={el}>
|
<div class="swiper" classList={{ 'cards-with-cover': isCardsWithCover }} ref={el}>
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">{props.children}</div>
|
||||||
<For each={articles()}>
|
|
||||||
{(a: Shout) => (
|
|
||||||
<ArticleCard
|
|
||||||
article={a}
|
|
||||||
settings={{
|
|
||||||
additionalClass: 'swiper-slide',
|
|
||||||
isFloorImportant: true,
|
|
||||||
isWithCover: isCardsWithCover,
|
|
||||||
nodate: true
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</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'} />
|
||||||
</div>
|
</div>
|
|
@ -15,6 +15,7 @@
|
||||||
"By alphabet": "По алфавиту",
|
"By alphabet": "По алфавиту",
|
||||||
"By authors": "По авторам",
|
"By authors": "По авторам",
|
||||||
"By name": "По имени",
|
"By name": "По имени",
|
||||||
|
"By popularity": "По популярности",
|
||||||
"By rating": "По популярности",
|
"By rating": "По популярности",
|
||||||
"By relevance": "По релевантности",
|
"By relevance": "По релевантности",
|
||||||
"By shouts": "По публикациям",
|
"By shouts": "По публикациям",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user