webapp/src/components/Views/Feed.tsx

187 lines
6.6 KiB
TypeScript
Raw Normal View History

2022-11-29 11:01:23 +00:00
import { createEffect, createMemo, createSignal, For, onMount, Show } from 'solid-js'
2022-09-09 11:53:35 +00:00
import '../../styles/Feed.scss'
2022-10-25 21:45:37 +00:00
import stylesBeside from '../../components/Feed/Beside.module.scss'
2022-11-14 17:41:05 +00:00
import { Icon } from '../_shared/Icon'
2022-09-09 11:53:35 +00:00
import { ArticleCard } from '../Feed/Card'
2022-09-13 09:59:04 +00:00
import { AuthorCard } from '../Author/Card'
2023-02-17 09:21:02 +00:00
2022-09-13 09:59:04 +00:00
import { FeedSidebar } from '../Feed/Sidebar'
2023-01-04 13:26:18 +00:00
import { Comment as CommentCard } from '../Article/Comment'
2022-11-18 02:23:04 +00:00
import { loadShouts, useArticlesStore } from '../../stores/zine/articles'
2022-09-09 11:53:35 +00:00
import { useAuthorsStore } from '../../stores/zine/authors'
2022-09-09 12:18:09 +00:00
import { useTopicsStore } from '../../stores/zine/topics'
2022-09-22 09:37:49 +00:00
import { useTopAuthorsStore } from '../../stores/zine/topAuthors'
2022-11-14 10:02:08 +00:00
import { useSession } from '../../context/session'
2023-01-25 22:13:01 +00:00
import stylesTopic from '../Feed/CardTopic.module.scss'
import styles from './Feed.module.scss'
import { clsx } from 'clsx'
2023-02-17 09:21:02 +00:00
import { useReactions } from '../../context/reactions'
import type { Reaction } from '../../graphql/types.gen'
import { getPagePath } from '@nanostores/router'
import { router } from '../../stores/router'
import { useLocalize } from '../../context/localize'
2022-09-09 11:53:35 +00:00
export const FEED_PAGE_SIZE = 20
export const FeedView = () => {
2023-02-17 09:21:02 +00:00
const { t } = useLocalize()
2022-09-09 11:53:35 +00:00
// state
2022-11-18 02:23:04 +00:00
const { sortedArticles } = useArticlesStore()
2022-09-28 20:16:44 +00:00
const { sortedAuthors } = useAuthorsStore()
const { topTopics } = useTopicsStore()
const { topAuthors } = useTopAuthorsStore()
2022-11-14 10:02:08 +00:00
const { session } = useSession()
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
2023-02-17 09:21:02 +00:00
const [topComments, setTopComments] = createSignal<Reaction[]>([])
2023-02-17 09:21:02 +00:00
const {
actions: { loadReactionsBy }
} = useReactions()
// TODO:
// const collaborativeShouts = createMemo(() =>
// sortedArticles().filter((shout) => shout.visibility === 'authors')
// )
// createEffect(async () => {
// if (collaborativeShouts()) {
// await loadReactionsBy({ by: { shouts: collaborativeShouts().map((shout) => shout.slug) }, limit: 5 })
// }
// })
2022-11-29 11:01:23 +00:00
2023-02-17 09:21:02 +00:00
const userSlug = createMemo(() => session()?.user?.slug)
2022-11-29 11:01:23 +00:00
createEffect(async () => {
2023-02-17 09:21:02 +00:00
if (userSlug()) {
2022-11-29 11:01:23 +00:00
// load recent editing shouts ( visibility = authors )
2023-02-17 09:21:02 +00:00
await loadShouts({ filters: { author: userSlug(), visibility: 'authors' }, limit: 15 })
2022-11-29 11:01:23 +00:00
}
})
const loadMore = async () => {
2022-11-18 02:23:04 +00:00
const { hasMore } = await loadShouts({
filters: { visibility: 'community' },
2022-11-15 14:24:50 +00:00
limit: FEED_PAGE_SIZE,
offset: sortedArticles().length
})
setIsLoadMoreButtonVisible(hasMore)
2022-09-13 09:59:04 +00:00
}
2022-11-16 06:33:58 +00:00
onMount(async () => {
// load recent shouts not only published ( visibility = community )
2023-02-17 09:21:02 +00:00
loadMore()
// load 5 recent comments overall
const comments = await loadReactionsBy({ by: { comment: true }, limit: 5 })
setTopComments(comments)
})
2022-09-09 11:53:35 +00:00
return (
<>
2023-01-25 22:13:01 +00:00
<div class="wide-container feed">
2023-01-30 23:09:33 +00:00
<div class="shift-content">
<div class={clsx('left-col', styles.feedNavigation)}>
2022-09-28 20:16:44 +00:00
<FeedSidebar authors={sortedAuthors()} />
2022-09-09 11:53:35 +00:00
</div>
2023-01-30 23:09:33 +00:00
<div class="row">
<div class="col-md-8">
<ul class="feed-filter">
<Show when={!!session()?.user?.slug}>
<li class="selected">
<a href="/feed/my">{t('My feed')}</a>
</li>
</Show>
<li>
<a href="/feed/?by=views">{t('Most read')}</a>
</li>
<li>
<a href="/feed/?by=rating">{t('Top rated')}</a>
</li>
<li>
<a href="/feed/?by=comments">{t('Most commented')}</a>
2022-09-09 11:53:35 +00:00
</li>
2022-09-09 12:18:09 +00:00
</ul>
2022-09-09 11:53:35 +00:00
2023-01-30 23:09:33 +00:00
<Show when={sortedArticles().length > 0}>
<For each={sortedArticles().slice(0, 4)}>
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
</For>
2022-09-09 11:53:35 +00:00
2023-01-30 23:09:33 +00:00
<div class={stylesBeside.besideColumnTitle}>
<h4>{t('Popular authors')}</h4>
<a href="/authors">
{t('All authors')}
<Icon name="arrow-right" class={stylesBeside.icon} />
</a>
</div>
<ul class={stylesBeside.besideColumn}>
<For each={topAuthors().slice(0, 5)}>
{(author) => (
<li>
<AuthorCard author={author} compact={true} hasLink={true} />
2023-01-26 21:42:47 +00:00
</li>
2023-01-30 23:09:33 +00:00
)}
</For>
</ul>
<For each={sortedArticles().slice(4)}>
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
2023-01-25 22:13:01 +00:00
</For>
2023-01-30 23:09:33 +00:00
</Show>
</div>
2023-01-25 22:13:01 +00:00
<aside class={clsx('col-md-3', styles.feedAside)}>
2023-01-25 22:13:01 +00:00
<section class={styles.asideSection}>
2023-01-30 23:09:33 +00:00
<h4>{t('Comments')}</h4>
<For each={topComments()}>
2023-02-17 09:21:02 +00:00
{(comment) => <CommentCard comment={comment} compact={true} />}
2022-09-09 11:53:35 +00:00
</For>
</section>
2023-01-25 22:13:01 +00:00
2023-01-30 23:09:33 +00:00
<Show when={topTopics().length > 0}>
<section class={styles.asideSection}>
<h4>{t('Topics')}</h4>
<For each={topTopics().slice(0, 5)}>
{(topic) => (
<span class={clsx(stylesTopic.shoutTopic, styles.topic)}>
<a href={`/topic/${topic.slug}`}>{topic.title}</a>{' '}
</span>
)}
</For>
</section>
</Show>
<section class={clsx(styles.asideSection, styles.pinnedLinks)}>
<Icon name="pin" class={styles.icon} />
<ul class="nodash">
<li>
2023-02-17 09:21:02 +00:00
<a href={getPagePath(router, 'guide')}>Как устроен Дискурс</a>
2023-01-30 23:09:33 +00:00
</li>
<li>
<a href="/how-to-write-a-good-article">Как создать хороший текст</a>
</li>
<li>
<a href="#">Правила конструктивных дискуссий</a>
</li>
<li>
2023-02-17 09:21:02 +00:00
<a href={getPagePath(router, 'principles')}>Принципы сообщества</a>
2023-01-30 23:09:33 +00:00
</li>
</ul>
</section>
</aside>
</div>
2022-09-09 11:53:35 +00:00
</div>
2023-01-30 23:09:33 +00:00
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={loadMore}>
{t('Load more')}
</button>
</p>
</Show>
2022-09-09 11:53:35 +00:00
</div>
</>
)
}