import { getPagePath } from '@nanostores/router' import { Meta } from '@solidjs/meta' import { clsx } from 'clsx' import { For, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' import { useLocalize } from '../../../context/localize' import { useReactions } from '../../../context/reactions' import { useSession } from '../../../context/session' import { apiClient } from '../../../graphql/client/core' import type { Author, LoadShoutsOptions, Reaction, Shout } from '../../../graphql/schema/core.gen' import { router, useRouter } from '../../../stores/router' import { showModal } from '../../../stores/ui' import { resetSortedArticles, useArticlesStore } from '../../../stores/zine/articles' import { useTopAuthorsStore } from '../../../stores/zine/topAuthors' import { useTopicsStore } from '../../../stores/zine/topics' import { getImageUrl } from '../../../utils/getImageUrl' import { CommentDate } from '../../Article/CommentDate' import { getShareUrl } from '../../Article/SharePopup' import { AuthorBadge } from '../../Author/AuthorBadge' import { AuthorLink } from '../../Author/AuthorLink' import { ArticleCard } from '../../Feed/ArticleCard' import { Sidebar } from '../../Feed/Sidebar' import { Modal } from '../../Nav/Modal' import { DropDown } from '../../_shared/DropDown' import { Icon } from '../../_shared/Icon' import { InviteMembers } from '../../_shared/InviteMembers' import { Loading } from '../../_shared/Loading' import { ShareModal } from '../../_shared/ShareModal' import stylesBeside from '../../Feed/Beside.module.scss' import stylesTopic from '../../Feed/CardTopic.module.scss' import styles from './Feed.module.scss' export const FEED_PAGE_SIZE = 20 const UNRATED_ARTICLES_COUNT = 5 type FeedPeriod = 'week' | 'month' | 'year' type VisibilityMode = 'all' | 'community' | 'featured' type PeriodItem = { value: FeedPeriod title: string } type VisibilityItem = { value: VisibilityMode title: string } type FeedSearchParams = { by: 'publish_date' | 'likes_stat' | 'rating' | 'last_comment' period: FeedPeriod visibility: VisibilityMode } const getOrderBy = (by: FeedSearchParams['by']) => { if (by === 'likes_stat' || by === 'rating') { return 'likes_stat' } if (by === 'last_comment') { return 'last_comment' } return '' } const getFromDate = (period: FeedPeriod): number => { const now = new Date() let d: Date = now switch (period) { case 'week': { d = new Date(now.setDate(now.getDate() - 7)) break } case 'month': { d = new Date(now.setMonth(now.getMonth() - 1)) break } case 'year': { d = new Date(now.setFullYear(now.getFullYear() - 1)) break } } return Math.floor(d.getTime() / 1000) } type Props = { loadShouts: (options: LoadShoutsOptions) => Promise<{ hasMore: boolean newShouts: Shout[] }> } export const FeedView = (props: Props) => { const { t } = useLocalize() const monthPeriod: PeriodItem = { value: 'month', title: t('This month') } const visibilityAll = { value: 'featured', title: t('All') } const periods: PeriodItem[] = [ { value: 'week', title: t('This week') }, monthPeriod, { value: 'year', title: t('This year') } ] const visibilities: VisibilityItem[] = [ { value: 'community', title: t('All') }, { value: 'featured', title: t('Published') } ] const { page, searchParams, changeSearchParams } = useRouter() const [isLoading, setIsLoading] = createSignal(false) const [isRightColumnLoaded, setIsRightColumnLoaded] = createSignal(false) const { session } = useSession() const { loadReactionsBy } = useReactions() const { sortedArticles } = useArticlesStore() const { topTopics } = useTopicsStore() const { topAuthors } = useTopAuthorsStore() const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const [topComments, setTopComments] = createSignal([]) const [unratedArticles, setUnratedArticles] = createSignal([]) const currentPeriod = createMemo(() => { const period = periods.find((p) => p.value === searchParams().period) if (!period) { return monthPeriod } return period }) const currentVisibility = createMemo(() => { const visibility = visibilities.find((v) => v.value === searchParams().visibility) if (!visibility) { return visibilityAll } return visibility }) const loadUnratedArticles = async () => { if (session()) { const result = await apiClient.getUnratedShouts(UNRATED_ARTICLES_COUNT) setUnratedArticles(result) } } const loadTopComments = async () => { const comments = await loadReactionsBy({ by: { comment: true }, limit: 5 }) setTopComments(comments) } onMount(() => { loadMore() // eslint-disable-next-line promise/catch-or-return Promise.all([loadTopComments()]).finally(() => setIsRightColumnLoaded(true)) }) createEffect(() => { if (session()?.access_token && !unratedArticles()) { loadUnratedArticles() } }) createEffect( on( () => page().route + searchParams().by + searchParams().period + searchParams().visibility, () => { resetSortedArticles() loadMore() }, { defer: true } ) ) const loadFeedShouts = () => { const options: LoadShoutsOptions = { limit: FEED_PAGE_SIZE, offset: sortedArticles().length } const orderBy = getOrderBy(searchParams().by) if (orderBy) { options.order_by = orderBy } const visibilityMode = searchParams().visibility if (visibilityMode === 'all') { options.filters = { ...options.filters } } else if (visibilityMode) { options.filters = { ...options.filters, featured: visibilityMode === 'featured' } } if (searchParams().by && searchParams().by !== 'publish_date') { const period = searchParams().period || 'month' options.filters = { after: getFromDate(period) } } return props.loadShouts(options) } const loadMore = async () => { setIsLoading(true) const { hasMore, newShouts } = await loadFeedShouts() setIsLoading(false) loadReactionsBy({ by: { shouts: newShouts.map((s) => s.slug) } }) setIsLoadMoreButtonVisible(hasMore) } const ogImage = getImageUrl('production/image/logo_image.png') const description = t( 'Independent media project about culture, science, art and society with horizontal editing' ) const ogTitle = t('Feed') const [shareData, setShareData] = createSignal() const handleShare = (shared) => { showModal('share') setShareData(shared) } return (
  • {t('Recent')}
  • {/*
  • */} {/* {t('Most read')}*/} {/*
  • */}
  • changeSearchParams({ by: 'rating' })}> {t('Top rated')}
  • changeSearchParams({ by: 'last_comment' })}> {t('Most commented')}
changeSearchParams({ period: period.value })} /> changeSearchParams({ visibility: visibility.value }) } />
}> 0}> {(article) => ( handleShare(shared)} onInvite={() => showModal('inviteMembers')} article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" /> )}

{t('Popular authors')}

{t('All authors')}
    {(author) => (
  • )}
{(article) => ( )}

) }