2023-11-14 15:10:00 +00:00
|
|
|
|
import { getPagePath } from '@nanostores/router'
|
|
|
|
|
import { clsx } from 'clsx'
|
2024-02-04 11:25:21 +00:00
|
|
|
|
import { For, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import { useLocalize } from '../../../context/localize'
|
2024-05-07 15:17:31 +00:00
|
|
|
|
import { Meta } from '../../../context/meta'
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import { useReactions } from '../../../context/reactions'
|
2023-12-26 10:05:15 +00:00
|
|
|
|
import { useSession } from '../../../context/session'
|
2024-05-06 23:44:25 +00:00
|
|
|
|
import { useTopics } from '../../../context/topics'
|
2023-12-18 01:15:49 +00:00
|
|
|
|
import { apiClient } from '../../../graphql/client/core'
|
2024-02-05 15:04:23 +00:00
|
|
|
|
import type { Author, LoadShoutsOptions, Reaction, Shout } from '../../../graphql/schema/core.gen'
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import { router, useRouter } from '../../../stores/router'
|
2024-01-08 13:02:52 +00:00
|
|
|
|
import { showModal } from '../../../stores/ui'
|
2024-02-04 11:25:21 +00:00
|
|
|
|
import { resetSortedArticles, useArticlesStore } from '../../../stores/zine/articles'
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import { useTopAuthorsStore } from '../../../stores/zine/topAuthors'
|
|
|
|
|
import { getImageUrl } from '../../../utils/getImageUrl'
|
2024-03-01 13:04:28 +00:00
|
|
|
|
import { byCreated } from '../../../utils/sortby'
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import { CommentDate } from '../../Article/CommentDate'
|
2024-01-08 13:02:52 +00:00
|
|
|
|
import { getShareUrl } from '../../Article/SharePopup'
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import { AuthorBadge } from '../../Author/AuthorBadge'
|
2023-12-31 05:01:34 +00:00
|
|
|
|
import { AuthorLink } from '../../Author/AuthorLink'
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import { ArticleCard } from '../../Feed/ArticleCard'
|
2024-05-10 16:52:13 +00:00
|
|
|
|
import { Placeholder } from '../../Feed/Placeholder'
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import { Sidebar } from '../../Feed/Sidebar'
|
2024-02-03 08:16:47 +00:00
|
|
|
|
import { Modal } from '../../Nav/Modal'
|
2024-02-04 11:25:21 +00:00
|
|
|
|
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'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
|
2023-12-14 18:45:50 +00:00
|
|
|
|
import stylesBeside from '../../Feed/Beside.module.scss'
|
|
|
|
|
import stylesTopic from '../../Feed/CardTopic.module.scss'
|
2024-02-04 11:25:21 +00:00
|
|
|
|
import styles from './Feed.module.scss'
|
2022-09-09 11:53:35 +00:00
|
|
|
|
|
2022-10-28 21:21:47 +00:00
|
|
|
|
export const FEED_PAGE_SIZE = 20
|
2023-12-14 18:45:50 +00:00
|
|
|
|
const UNRATED_ARTICLES_COUNT = 5
|
2022-10-28 21:21:47 +00:00
|
|
|
|
|
2023-12-20 08:07:57 +00:00
|
|
|
|
type FeedPeriod = 'week' | 'month' | 'year'
|
2024-02-02 17:29:53 +00:00
|
|
|
|
type VisibilityMode = 'all' | 'community' | 'featured'
|
2023-12-20 08:07:57 +00:00
|
|
|
|
|
|
|
|
|
type PeriodItem = {
|
|
|
|
|
value: FeedPeriod
|
|
|
|
|
title: string
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 16:43:52 +00:00
|
|
|
|
type VisibilityItem = {
|
|
|
|
|
value: VisibilityMode
|
|
|
|
|
title: string
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-07 16:53:01 +00:00
|
|
|
|
type FeedSearchParams = {
|
2024-05-01 14:33:37 +00:00
|
|
|
|
by: 'publish_date' | 'likes' | 'last_comment'
|
2023-12-20 08:07:57 +00:00
|
|
|
|
period: FeedPeriod
|
2023-12-29 16:43:52 +00:00
|
|
|
|
visibility: VisibilityMode
|
2023-07-07 16:53:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-04-24 12:48:19 +00:00
|
|
|
|
type Props = {
|
|
|
|
|
loadShouts: (options: LoadShoutsOptions) => Promise<{
|
|
|
|
|
hasMore: boolean
|
|
|
|
|
newShouts: Shout[]
|
|
|
|
|
}>
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-24 13:08:04 +00:00
|
|
|
|
const getFromDate = (period: FeedPeriod): number => {
|
2023-12-21 10:39:26 +00:00
|
|
|
|
const now = new Date()
|
2023-12-24 13:08:04 +00:00
|
|
|
|
let d: Date = now
|
2023-12-21 10:39:26 +00:00
|
|
|
|
switch (period) {
|
|
|
|
|
case 'week': {
|
2023-12-24 13:08:04 +00:00
|
|
|
|
d = new Date(now.setDate(now.getDate() - 7))
|
2023-12-24 13:32:25 +00:00
|
|
|
|
break
|
2023-12-21 10:39:26 +00:00
|
|
|
|
}
|
|
|
|
|
case 'month': {
|
2023-12-24 13:08:04 +00:00
|
|
|
|
d = new Date(now.setMonth(now.getMonth() - 1))
|
2023-12-24 13:32:25 +00:00
|
|
|
|
break
|
2023-12-21 10:39:26 +00:00
|
|
|
|
}
|
|
|
|
|
case 'year': {
|
2023-12-24 13:08:04 +00:00
|
|
|
|
d = new Date(now.setFullYear(now.getFullYear() - 1))
|
2023-12-24 13:32:25 +00:00
|
|
|
|
break
|
2023-12-21 10:39:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-24 13:08:04 +00:00
|
|
|
|
return Math.floor(d.getTime() / 1000)
|
2023-12-21 10:39:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-29 12:48:58 +00:00
|
|
|
|
export const FeedView = (props: Props) => {
|
2023-12-20 16:54:20 +00:00
|
|
|
|
const { t } = useLocalize()
|
2023-12-20 08:07:57 +00:00
|
|
|
|
|
|
|
|
|
const monthPeriod: PeriodItem = { value: 'month', title: t('This month') }
|
|
|
|
|
|
|
|
|
|
const periods: PeriodItem[] = [
|
|
|
|
|
{ value: 'week', title: t('This week') },
|
|
|
|
|
monthPeriod,
|
|
|
|
|
{ value: 'year', title: t('This year') },
|
|
|
|
|
]
|
|
|
|
|
|
2023-12-29 16:43:52 +00:00
|
|
|
|
const visibilities: VisibilityItem[] = [
|
|
|
|
|
{ value: 'community', title: t('All') },
|
2024-02-02 17:29:53 +00:00
|
|
|
|
{ value: 'featured', title: t('Published') },
|
2023-12-29 16:43:52 +00:00
|
|
|
|
]
|
|
|
|
|
|
2023-12-20 08:07:57 +00:00
|
|
|
|
const { page, searchParams, changeSearchParams } = useRouter<FeedSearchParams>()
|
2023-07-07 16:53:01 +00:00
|
|
|
|
const [isLoading, setIsLoading] = createSignal(false)
|
2023-12-18 13:22:20 +00:00
|
|
|
|
const [isRightColumnLoaded, setIsRightColumnLoaded] = createSignal(false)
|
2024-05-10 16:52:13 +00:00
|
|
|
|
const { author, session } = useSession()
|
2024-02-04 17:40:15 +00:00
|
|
|
|
const { loadReactionsBy } = useReactions()
|
2022-11-18 02:23:04 +00:00
|
|
|
|
const { sortedArticles } = useArticlesStore()
|
2024-05-06 23:44:25 +00:00
|
|
|
|
const { topTopics } = useTopics()
|
2022-09-28 20:16:44 +00:00
|
|
|
|
const { topAuthors } = useTopAuthorsStore()
|
2022-10-28 21:21:47 +00:00
|
|
|
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
2023-02-17 09:21:02 +00:00
|
|
|
|
const [topComments, setTopComments] = createSignal<Reaction[]>([])
|
2023-12-14 18:45:50 +00:00
|
|
|
|
const [unratedArticles, setUnratedArticles] = createSignal<Shout[]>([])
|
2022-10-28 21:21:47 +00:00
|
|
|
|
|
2023-12-20 08:07:57 +00:00
|
|
|
|
const currentPeriod = createMemo(() => {
|
|
|
|
|
const period = periods.find((p) => p.value === searchParams().period)
|
|
|
|
|
if (!period) {
|
|
|
|
|
return monthPeriod
|
|
|
|
|
}
|
|
|
|
|
return period
|
|
|
|
|
})
|
|
|
|
|
|
2023-12-29 16:43:52 +00:00
|
|
|
|
const currentVisibility = createMemo(() => {
|
|
|
|
|
const visibility = visibilities.find((v) => v.value === searchParams().visibility)
|
|
|
|
|
if (!visibility) {
|
2024-04-24 12:48:19 +00:00
|
|
|
|
return visibilities[0]
|
2023-12-29 16:43:52 +00:00
|
|
|
|
}
|
|
|
|
|
return visibility
|
|
|
|
|
})
|
|
|
|
|
|
2023-12-14 18:45:50 +00:00
|
|
|
|
const loadUnratedArticles = async () => {
|
2024-01-18 12:52:02 +00:00
|
|
|
|
if (session()) {
|
|
|
|
|
const result = await apiClient.getUnratedShouts(UNRATED_ARTICLES_COUNT)
|
|
|
|
|
setUnratedArticles(result)
|
|
|
|
|
}
|
2023-12-14 18:45:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-18 13:22:20 +00:00
|
|
|
|
const loadTopComments = async () => {
|
2024-02-29 17:51:07 +00:00
|
|
|
|
const comments = await loadReactionsBy({ by: { comment: true }, limit: 50 })
|
2024-03-01 13:04:28 +00:00
|
|
|
|
setTopComments(comments.sort(byCreated).reverse())
|
2023-12-18 13:22:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-01 14:28:50 +00:00
|
|
|
|
onMount(() => {
|
|
|
|
|
loadMore()
|
2023-12-18 13:22:20 +00:00
|
|
|
|
// eslint-disable-next-line promise/catch-or-return
|
2024-01-18 12:52:02 +00:00
|
|
|
|
Promise.all([loadTopComments()]).finally(() => setIsRightColumnLoaded(true))
|
2023-12-25 04:01:52 +00:00
|
|
|
|
})
|
|
|
|
|
|
2024-05-20 23:15:52 +00:00
|
|
|
|
createEffect(
|
|
|
|
|
on(
|
|
|
|
|
[() => session(), unratedArticles],
|
|
|
|
|
([s, seen]) => {
|
|
|
|
|
if (s?.access_token && !(seen?.length > 0)) loadUnratedArticles()
|
|
|
|
|
},
|
|
|
|
|
{ defer: true },
|
|
|
|
|
),
|
|
|
|
|
)
|
2023-09-01 14:28:50 +00:00
|
|
|
|
|
2023-07-07 16:53:01 +00:00
|
|
|
|
createEffect(
|
|
|
|
|
on(
|
2024-05-20 23:15:52 +00:00
|
|
|
|
[page, searchParams],
|
|
|
|
|
(_, _p) => {
|
2023-07-07 16:53:01 +00:00
|
|
|
|
resetSortedArticles()
|
|
|
|
|
loadMore()
|
2023-09-01 14:28:50 +00:00
|
|
|
|
},
|
2023-11-14 15:10:00 +00:00
|
|
|
|
{ defer: true },
|
|
|
|
|
),
|
2023-07-07 16:53:01 +00:00
|
|
|
|
)
|
2023-12-20 08:07:57 +00:00
|
|
|
|
|
2023-07-07 16:53:01 +00:00
|
|
|
|
const loadFeedShouts = () => {
|
|
|
|
|
const options: LoadShoutsOptions = {
|
2022-11-15 14:24:50 +00:00
|
|
|
|
limit: FEED_PAGE_SIZE,
|
2023-11-14 15:10:00 +00:00
|
|
|
|
offset: sortedArticles().length,
|
2023-07-07 16:53:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-01 13:04:28 +00:00
|
|
|
|
if (searchParams()?.by) {
|
|
|
|
|
options.order_by = searchParams().by
|
2023-07-07 16:53:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 16:43:52 +00:00
|
|
|
|
const visibilityMode = searchParams().visibility
|
2024-04-24 12:48:19 +00:00
|
|
|
|
|
2024-01-05 18:38:35 +00:00
|
|
|
|
if (visibilityMode === 'all') {
|
|
|
|
|
options.filters = { ...options.filters }
|
|
|
|
|
} else if (visibilityMode) {
|
2024-02-02 17:29:53 +00:00
|
|
|
|
options.filters = {
|
|
|
|
|
...options.filters,
|
|
|
|
|
featured: visibilityMode === 'featured',
|
|
|
|
|
}
|
2023-12-29 16:43:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-20 08:07:57 +00:00
|
|
|
|
if (searchParams().by && searchParams().by !== 'publish_date') {
|
|
|
|
|
const period = searchParams().period || 'month'
|
2023-12-24 13:08:04 +00:00
|
|
|
|
options.filters = { after: getFromDate(period) }
|
2023-12-20 08:07:57 +00:00
|
|
|
|
}
|
2024-04-24 12:48:19 +00:00
|
|
|
|
|
2023-09-29 12:48:58 +00:00
|
|
|
|
return props.loadShouts(options)
|
2023-07-07 16:53:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const loadMore = async () => {
|
|
|
|
|
setIsLoading(true)
|
|
|
|
|
const { hasMore, newShouts } = await loadFeedShouts()
|
2023-08-17 16:00:53 +00:00
|
|
|
|
|
2023-07-07 16:53:01 +00:00
|
|
|
|
setIsLoading(false)
|
2023-02-28 17:13:14 +00:00
|
|
|
|
|
|
|
|
|
loadReactionsBy({
|
|
|
|
|
by: {
|
2023-11-14 15:10:00 +00:00
|
|
|
|
shouts: newShouts.map((s) => s.slug),
|
|
|
|
|
},
|
2023-02-28 17:13:14 +00:00
|
|
|
|
})
|
|
|
|
|
|
2022-10-28 21:21:47 +00:00
|
|
|
|
setIsLoadMoreButtonVisible(hasMore)
|
2022-09-13 09:59:04 +00:00
|
|
|
|
}
|
2022-10-28 21:21:47 +00:00
|
|
|
|
|
2023-12-13 10:39:31 +00:00
|
|
|
|
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')
|
|
|
|
|
|
2024-01-08 13:02:52 +00:00
|
|
|
|
const [shareData, setShareData] = createSignal<Shout | undefined>()
|
2024-03-01 13:04:28 +00:00
|
|
|
|
const handleShare = (shared: Shout | undefined) => {
|
2024-01-08 13:02:52 +00:00
|
|
|
|
showModal('share')
|
|
|
|
|
setShareData(shared)
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
|
return (
|
2023-09-29 12:48:58 +00:00
|
|
|
|
<div class="wide-container feed">
|
2023-12-13 10:39:31 +00:00
|
|
|
|
<Meta name="descprition" content={description} />
|
|
|
|
|
<Meta name="keywords" content={t('keywords')} />
|
|
|
|
|
<Meta name="og:type" content="article" />
|
|
|
|
|
<Meta name="og:title" content={ogTitle} />
|
|
|
|
|
<Meta name="og:image" content={ogImage} />
|
|
|
|
|
<Meta name="twitter:image" content={ogImage} />
|
|
|
|
|
<Meta name="og:description" content={description} />
|
|
|
|
|
<Meta name="twitter:card" content="summary_large_image" />
|
|
|
|
|
<Meta name="twitter:title" content={ogTitle} />
|
|
|
|
|
<Meta name="twitter:description" content={description} />
|
2023-09-29 12:48:58 +00:00
|
|
|
|
<div class="row">
|
|
|
|
|
<div class={clsx('col-md-5 col-xl-4', styles.feedNavigation)}>
|
2023-10-23 11:15:19 +00:00
|
|
|
|
<Sidebar />
|
2023-09-29 12:48:58 +00:00
|
|
|
|
</div>
|
2023-03-10 17:42:48 +00:00
|
|
|
|
|
2023-09-29 12:48:58 +00:00
|
|
|
|
<div class="col-md-12 offset-xl-1">
|
2024-05-18 22:03:06 +00:00
|
|
|
|
<Show when={!author() && page().route !== 'feed'}>
|
|
|
|
|
<Placeholder type={page().route} mode="feed" />
|
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
<Show when={(author() || page().route === 'feed') && sortedArticles().length}>
|
2024-05-10 16:52:13 +00:00
|
|
|
|
<div class={styles.filtersContainer}>
|
|
|
|
|
<ul class={clsx('view-switcher', styles.feedFilter)}>
|
|
|
|
|
<li
|
|
|
|
|
class={clsx({
|
|
|
|
|
'view-switcher__item--selected':
|
|
|
|
|
searchParams().by === 'publish_date' || !searchParams().by,
|
|
|
|
|
})}
|
|
|
|
|
>
|
|
|
|
|
<a href={getPagePath(router, page().route)}>{t('Recent')}</a>
|
|
|
|
|
</li>
|
|
|
|
|
{/*<li>*/}
|
|
|
|
|
{/* <a href="/feed/?by=views">{t('Most read')}</a>*/}
|
|
|
|
|
{/*</li>*/}
|
|
|
|
|
<li
|
|
|
|
|
class={clsx({
|
|
|
|
|
'view-switcher__item--selected': searchParams().by === 'likes',
|
|
|
|
|
})}
|
|
|
|
|
>
|
|
|
|
|
<span class="link" onClick={() => changeSearchParams({ by: 'likes' })}>
|
|
|
|
|
{t('Top rated')}
|
|
|
|
|
</span>
|
|
|
|
|
</li>
|
|
|
|
|
<li
|
|
|
|
|
class={clsx({
|
|
|
|
|
'view-switcher__item--selected': searchParams().by === 'last_comment',
|
|
|
|
|
})}
|
|
|
|
|
>
|
|
|
|
|
<span class="link" onClick={() => changeSearchParams({ by: 'last_comment' })}>
|
|
|
|
|
{t('Most commented')}
|
|
|
|
|
</span>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
<div class={styles.dropdowns}>
|
|
|
|
|
<Show when={searchParams().by && searchParams().by !== 'publish_date'}>
|
|
|
|
|
<DropDown
|
|
|
|
|
popupProps={{ horizontalAnchor: 'right' }}
|
|
|
|
|
options={periods}
|
|
|
|
|
currentOption={currentPeriod()}
|
|
|
|
|
triggerCssClass={styles.periodSwitcher}
|
|
|
|
|
onChange={(period: PeriodItem) => changeSearchParams({ period: period.value })}
|
|
|
|
|
/>
|
|
|
|
|
</Show>
|
2023-12-20 08:07:57 +00:00
|
|
|
|
<DropDown
|
2024-01-06 04:06:58 +00:00
|
|
|
|
popupProps={{ horizontalAnchor: 'right' }}
|
2024-05-10 16:52:13 +00:00
|
|
|
|
options={visibilities}
|
|
|
|
|
currentOption={currentVisibility()}
|
2023-12-20 08:07:57 +00:00
|
|
|
|
triggerCssClass={styles.periodSwitcher}
|
2024-05-10 16:52:13 +00:00
|
|
|
|
onChange={(visibility: VisibilityItem) =>
|
|
|
|
|
changeSearchParams({ visibility: visibility.value })
|
|
|
|
|
}
|
2023-12-20 08:07:57 +00:00
|
|
|
|
/>
|
2024-05-10 16:52:13 +00:00
|
|
|
|
</div>
|
2023-12-29 16:43:52 +00:00
|
|
|
|
</div>
|
2023-08-12 14:17:00 +00:00
|
|
|
|
|
2024-05-10 16:52:13 +00:00
|
|
|
|
<Show when={!isLoading()} fallback={<Loading />}>
|
|
|
|
|
<Show when={sortedArticles().length > 0}>
|
|
|
|
|
<For each={sortedArticles().slice(0, 4)}>
|
|
|
|
|
{(article) => (
|
|
|
|
|
<ArticleCard
|
|
|
|
|
onShare={(shared) => handleShare(shared)}
|
|
|
|
|
onInvite={() => showModal('inviteMembers')}
|
|
|
|
|
article={article}
|
|
|
|
|
settings={{ isFeedMode: true }}
|
|
|
|
|
desktopCoverSize="M"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
|
|
|
|
|
|
|
|
|
<div class={styles.asideSection}>
|
|
|
|
|
<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>
|
|
|
|
|
<AuthorBadge author={author} />
|
|
|
|
|
</li>
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
2023-09-24 14:55:46 +00:00
|
|
|
|
|
2024-05-10 16:52:13 +00:00
|
|
|
|
<For each={sortedArticles().slice(4)}>
|
|
|
|
|
{(article) => (
|
|
|
|
|
<ArticleCard article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" />
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
|
|
|
|
</Show>
|
2023-09-24 14:55:46 +00:00
|
|
|
|
|
2024-05-10 16:52:13 +00:00
|
|
|
|
<Show when={isLoadMoreButtonVisible()}>
|
|
|
|
|
<p class="load-more-container">
|
|
|
|
|
<button class="button" onClick={loadMore}>
|
|
|
|
|
{t('Load more')}
|
|
|
|
|
</button>
|
|
|
|
|
</p>
|
|
|
|
|
</Show>
|
2023-09-29 12:48:58 +00:00
|
|
|
|
</Show>
|
|
|
|
|
</Show>
|
|
|
|
|
</div>
|
2023-03-10 17:42:48 +00:00
|
|
|
|
|
2023-09-29 12:48:58 +00:00
|
|
|
|
<aside class={clsx('col-md-7 col-xl-6 offset-xl-1', styles.feedAside)}>
|
2023-12-18 13:22:20 +00:00
|
|
|
|
<Show when={isRightColumnLoaded()}>
|
|
|
|
|
<Show when={topComments().length > 0}>
|
|
|
|
|
<section class={styles.asideSection}>
|
|
|
|
|
<h4>{t('Comments')}</h4>
|
|
|
|
|
<For each={topComments()}>
|
|
|
|
|
{(comment) => {
|
|
|
|
|
return (
|
|
|
|
|
<div class={styles.comment}>
|
|
|
|
|
<div class={clsx('text-truncate', styles.commentBody)}>
|
|
|
|
|
<a
|
|
|
|
|
href={`${getPagePath(router, 'article', {
|
|
|
|
|
slug: comment.shout.slug,
|
|
|
|
|
})}?commentId=${comment.id}`}
|
|
|
|
|
innerHTML={comment.body}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div class={styles.commentDetails}>
|
2023-12-20 16:54:20 +00:00
|
|
|
|
<AuthorLink author={comment.created_by as Author} size={'XS'} />
|
2023-12-18 13:22:20 +00:00
|
|
|
|
<CommentDate comment={comment} isShort={true} isLastInRow={true} />
|
|
|
|
|
</div>
|
|
|
|
|
<div class={clsx('text-truncate', styles.commentArticleTitle)}>
|
|
|
|
|
<a href={`/${comment.shout.slug}`}>{comment.shout.title}</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}}
|
|
|
|
|
</For>
|
|
|
|
|
</section>
|
|
|
|
|
</Show>
|
2023-09-29 12:48:58 +00:00
|
|
|
|
|
2023-12-18 13:22:20 +00:00
|
|
|
|
<Show when={topTopics().length > 0}>
|
|
|
|
|
<section class={styles.asideSection}>
|
|
|
|
|
<h4>{t('Hot topics')}</h4>
|
|
|
|
|
<For each={topTopics().slice(0, 7)}>
|
|
|
|
|
{(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)}>
|
|
|
|
|
<h4>{t('Knowledge base')}</h4>
|
|
|
|
|
<ul class="nodash">
|
|
|
|
|
<li>
|
|
|
|
|
<a href={getPagePath(router, 'guide')}>Как устроен Дискурс</a>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<a href="/how-to-write-a-good-article">Как создать хороший текст</a>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<a href="#">Правила конструктивных дискуссий</a>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<a href={getPagePath(router, 'principles')}>Принципы сообщества</a>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
2023-12-14 18:45:50 +00:00
|
|
|
|
</section>
|
2024-01-13 14:14:35 +00:00
|
|
|
|
<Show when={unratedArticles()}>
|
2023-12-18 13:22:20 +00:00
|
|
|
|
<section class={clsx(styles.asideSection)}>
|
|
|
|
|
<h4>{t('Be the first to rate')}</h4>
|
|
|
|
|
<For each={unratedArticles()}>
|
|
|
|
|
{(article) => (
|
|
|
|
|
<ArticleCard article={article} settings={{ noimage: true, nodate: true }} />
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
|
|
|
|
</section>
|
|
|
|
|
</Show>
|
2023-12-14 18:45:50 +00:00
|
|
|
|
</Show>
|
2023-09-29 12:48:58 +00:00
|
|
|
|
</aside>
|
|
|
|
|
</div>
|
2024-01-08 13:02:52 +00:00
|
|
|
|
<Show when={shareData()}>
|
|
|
|
|
<ShareModal
|
|
|
|
|
title={shareData().title}
|
|
|
|
|
description={shareData().description}
|
|
|
|
|
imageUrl={shareData().cover}
|
|
|
|
|
shareUrl={getShareUrl({ pathname: `/${shareData().slug}` })}
|
|
|
|
|
/>
|
|
|
|
|
</Show>
|
2024-02-03 05:19:15 +00:00
|
|
|
|
|
|
|
|
|
<Modal variant="medium" name="inviteCoauthors">
|
|
|
|
|
<InviteMembers variant={'coauthors'} title={t('Invite experts')} />
|
|
|
|
|
</Modal>
|
2023-04-29 13:43:50 +00:00
|
|
|
|
</div>
|
2022-09-09 11:53:35 +00:00
|
|
|
|
)
|
|
|
|
|
}
|