diff --git a/src/components/Author/Full.tsx b/src/components/Author/Full.tsx index 9f869f7e..b83ed413 100644 --- a/src/components/Author/Full.tsx +++ b/src/components/Author/Full.tsx @@ -2,7 +2,7 @@ import type { Author } from '../../graphql/types.gen' import { AuthorCard } from './Card' import './Full.scss' -export default (props: { author: Author }) => { +export const AuthorFull = (props: { author: Author }) => { return (
diff --git a/src/components/Feed/Beside.tsx b/src/components/Feed/Beside.tsx index 21b28f19..3f0e91df 100644 --- a/src/components/Feed/Beside.tsx +++ b/src/components/Feed/Beside.tsx @@ -21,7 +21,7 @@ interface BesideProps { iconButton?: boolean } -export default (props: BesideProps) => { +export const Beside = (props: BesideProps) => { return ( 0}>
diff --git a/src/components/Feed/List.tsx b/src/components/Feed/List.tsx index dac7e127..055378a4 100644 --- a/src/components/Feed/List.tsx +++ b/src/components/Feed/List.tsx @@ -1,7 +1,7 @@ import { For, Suspense } from 'solid-js/web' -import OneWide from './Row1' -import Row2 from './Row2' -import Row3 from './Row3' +import { Row1 } from './Row1' +import { Row2 } from './Row2' +import { Row3 } from './Row3' import { shuffle } from '../../utils' import { createMemo, createSignal } from 'solid-js' import type { JSX } from 'solid-js' @@ -10,7 +10,7 @@ import './List.scss' import { t } from '../../utils/intl' export const Block6 = (props: { articles: Shout[] }) => { - const dice = createMemo(() => shuffle([OneWide, Row2, Row3])) + const dice = createMemo(() => shuffle([Row1, Row2, Row3])) return ( <> diff --git a/src/components/Feed/Row1.tsx b/src/components/Feed/Row1.tsx index b654fb82..bfb68aca 100644 --- a/src/components/Feed/Row1.tsx +++ b/src/components/Feed/Row1.tsx @@ -2,7 +2,7 @@ import { Show } from 'solid-js' import type { Shout } from '../../graphql/types.gen' import { ArticleCard } from './Card' -export default (props: { article: Shout }) => ( +export const Row1 = (props: { article: Shout }) => (
diff --git a/src/components/Feed/Row2.tsx b/src/components/Feed/Row2.tsx index e12b22bd..274317a8 100644 --- a/src/components/Feed/Row2.tsx +++ b/src/components/Feed/Row2.tsx @@ -2,13 +2,14 @@ import { createComputed, createSignal, Show } from 'solid-js' import { For } from 'solid-js/web' import type { Shout } from '../../graphql/types.gen' import { ArticleCard } from './Card' + const x = [ ['6', '6'], ['4', '8'], ['8', '4'] ] -export default (props: { articles: Shout[] }) => { +export const Row2 = (props: { articles: Shout[] }) => { const [y, setY] = createSignal(0) createComputed(() => setY(Math.floor(Math.random() * x.length))) diff --git a/src/components/Feed/Row3.tsx b/src/components/Feed/Row3.tsx index 6af65f3e..4687cb2f 100644 --- a/src/components/Feed/Row3.tsx +++ b/src/components/Feed/Row3.tsx @@ -2,7 +2,7 @@ import { For } from 'solid-js/web' import type { Shout } from '../../graphql/types.gen' import { ArticleCard } from './Card' -export default (props: { articles: Shout[]; header?: any }) => { +export const Row3 = (props: { articles: Shout[]; header?: any }) => { return (
diff --git a/src/components/Pages/AuthorPage.tsx b/src/components/Pages/AuthorPage.tsx index 0eab1346..d8d73f6c 100644 --- a/src/components/Pages/AuthorPage.tsx +++ b/src/components/Pages/AuthorPage.tsx @@ -1,8 +1,8 @@ import { MainLayout } from '../Layouts/MainLayout' -import { AuthorView } from '../Views/Author' +import { AuthorView, PRERENDERED_ARTICLES_COUNT } from '../Views/Author' import type { PageProps } from '../types' import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js' -import { loadArticlesForAuthors, resetSortedArticles } from '../../stores/zine/articles' +import { loadAuthorArticles, resetSortedArticles } from '../../stores/zine/articles' import { useRouter } from '../../stores/router' import { loadAuthor } from '../../stores/zine/authors' import { Loading } from '../Loading' @@ -27,7 +27,7 @@ export const AuthorPage = (props: PageProps) => { return } - await loadArticlesForAuthors({ authorSlugs: [slug()] }) + await loadAuthorArticles({ authorSlug: slug(), limit: PRERENDERED_ARTICLES_COUNT }) await loadAuthor({ slug: slug() }) setIsLoaded(true) diff --git a/src/components/Pages/FeedPage.tsx b/src/components/Pages/FeedPage.tsx index 13c18136..7aef8fbf 100644 --- a/src/components/Pages/FeedPage.tsx +++ b/src/components/Pages/FeedPage.tsx @@ -1,30 +1,14 @@ import { MainLayout } from '../Layouts/MainLayout' import { FeedView } from '../Views/Feed' -import type { PageProps } from '../types' -import { createSignal, onCleanup, onMount, Show } from 'solid-js' -import { loadRecentArticles, resetSortedArticles } from '../../stores/zine/articles' -import { Loading } from '../Loading' - -export const FeedPage = (props: PageProps) => { - const [isLoaded, setIsLoaded] = createSignal(Boolean(props.feedArticles)) - - onMount(async () => { - if (isLoaded()) { - return - } - - await loadRecentArticles({ limit: 50, offset: 0 }) - - setIsLoaded(true) - }) +import { onCleanup } from 'solid-js' +import { resetSortedArticles } from '../../stores/zine/articles' +export const FeedPage = () => { onCleanup(() => resetSortedArticles()) return ( - }> - - + ) } diff --git a/src/components/Pages/HomePage.tsx b/src/components/Pages/HomePage.tsx index f8430e03..392280bb 100644 --- a/src/components/Pages/HomePage.tsx +++ b/src/components/Pages/HomePage.tsx @@ -1,4 +1,4 @@ -import { HomeView } from '../Views/Home' +import { HomeView, PRERENDERED_ARTICLES_COUNT } from '../Views/Home' import { MainLayout } from '../Layouts/MainLayout' import type { PageProps } from '../types' import { createSignal, onCleanup, onMount, Show } from 'solid-js' @@ -14,7 +14,7 @@ export const HomePage = (props: PageProps) => { return } - await loadPublishedArticles({ limit: 5, offset: 0 }) + await loadPublishedArticles({ limit: PRERENDERED_ARTICLES_COUNT, offset: 0 }) await loadRandomTopics() setIsLoaded(true) diff --git a/src/components/Pages/TopicPage.tsx b/src/components/Pages/TopicPage.tsx index 7cbaa1b5..16e0c95a 100644 --- a/src/components/Pages/TopicPage.tsx +++ b/src/components/Pages/TopicPage.tsx @@ -1,8 +1,8 @@ import { MainLayout } from '../Layouts/MainLayout' -import { TopicView } from '../Views/Topic' +import { PRERENDERED_ARTICLES_COUNT, TopicView } from '../Views/Topic' import type { PageProps } from '../types' import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js' -import { loadArticlesForTopics, resetSortedArticles } from '../../stores/zine/articles' +import { loadTopicArticles, resetSortedArticles } from '../../stores/zine/articles' import { useRouter } from '../../stores/router' import { loadTopic } from '../../stores/zine/topics' import { Loading } from '../Loading' @@ -27,7 +27,7 @@ export const TopicPage = (props: PageProps) => { return } - await loadArticlesForTopics({ topicSlugs: [slug()] }) + await loadTopicArticles({ topicSlug: slug(), limit: PRERENDERED_ARTICLES_COUNT, offset: 0 }) await loadTopic({ slug: slug() }) setIsLoaded(true) diff --git a/src/components/Views/Author.tsx b/src/components/Views/Author.tsx index 4c84b7c5..52cd189f 100644 --- a/src/components/Views/Author.tsx +++ b/src/components/Views/Author.tsx @@ -1,17 +1,18 @@ -import { Show, createMemo } from 'solid-js' +import { Show, createMemo, createSignal, For, onMount } from 'solid-js' import type { Author, Shout } from '../../graphql/types.gen' -import Row2 from '../Feed/Row2' -import Row3 from '../Feed/Row3' -// import Beside from '../Feed/Beside' -import AuthorFull from '../Author/Full' +import { Row2 } from '../Feed/Row2' +import { Row3 } from '../Feed/Row3' +import { AuthorFull } from '../Author/Full' import { t } from '../../utils/intl' import { useAuthorsStore } from '../../stores/zine/authors' -import { useArticlesStore } from '../../stores/zine/articles' +import { loadAuthorArticles, useArticlesStore } from '../../stores/zine/articles' import '../../styles/Topic.scss' import { useTopicsStore } from '../../stores/zine/topics' import { useRouter } from '../../stores/router' -import Beside from '../Feed/Beside' +import { Beside } from '../Feed/Beside' +import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll' +import { splitToPages } from '../../utils/splitToPages' // TODO: load reactions on client type AuthorProps = { @@ -26,16 +27,37 @@ type AuthorPageSearchParams = { by: '' | 'viewed' | 'rating' | 'commented' | 'recent' } +export const PRERENDERED_ARTICLES_COUNT = 12 +const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3 + export const AuthorView = (props: AuthorProps) => { const { sortedArticles } = useArticlesStore({ sortedArticles: props.authorArticles }) const { authorEntities } = useAuthorsStore({ authors: [props.author] }) const { topicsByAuthor } = useTopicsStore() + const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const author = createMemo(() => authorEntities()[props.authorSlug]) const { searchParams, changeSearchParam } = useRouter() + const loadMore = async () => { + saveScrollPosition() + const { hasMore } = await loadAuthorArticles({ + authorSlug: author().slug, + limit: LOAD_MORE_PAGE_SIZE, + offset: sortedArticles().length + }) + setIsLoadMoreButtonVisible(hasMore) + restoreScrollPosition() + } + + onMount(async () => { + if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) { + loadMore() + } + }) + const title = createMemo(() => { const m = searchParams().by if (m === 'viewed') return t('Top viewed') @@ -44,6 +66,10 @@ export const AuthorView = (props: AuthorProps) => { return t('Top recent') }) + const pages = createMemo(() => + splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE) + ) + return (
{t('Loading')}
}> @@ -83,31 +109,39 @@ export const AuthorView = (props: AuthorProps) => {

{title()}

+
- 0}> - - + + + + + - 4}> - - + + {(page) => ( + <> + + + + + )} + - 6}> - - - - 9}> - - + +

+ +

diff --git a/src/components/Views/Feed.tsx b/src/components/Views/Feed.tsx index af1c07a2..c791331c 100644 --- a/src/components/Views/Feed.tsx +++ b/src/components/Views/Feed.tsx @@ -1,5 +1,4 @@ -import { createMemo, For, Show } from 'solid-js' -import type { Shout, Reaction } from '../../graphql/types.gen' +import { createMemo, createSignal, For, onMount, Show } from 'solid-js' import '../../styles/Feed.scss' import stylesBeside from '../../components/Feed/Beside.module.scss' import { Icon } from '../Nav/Icon' @@ -17,11 +16,6 @@ import { useAuthorsStore } from '../../stores/zine/authors' import { useTopicsStore } from '../../stores/zine/topics' import { useTopAuthorsStore } from '../../stores/zine/topAuthors' -interface FeedProps { - articles: Shout[] - reactions?: Reaction[] -} - // const AUTHORSHIP_REACTIONS = [ // ReactionKind.Accept, // ReactionKind.Reject, @@ -29,9 +23,11 @@ interface FeedProps { // ReactionKind.Ask // ] -export const FeedView = (props: FeedProps) => { +export const FEED_PAGE_SIZE = 20 + +export const FeedView = () => { // state - const { sortedArticles } = useArticlesStore({ sortedArticles: props.articles }) + const { sortedArticles } = useArticlesStore() const reactions = useReactionsStore() const { sortedAuthors } = useAuthorsStore() const { topTopics } = useTopicsStore() @@ -40,6 +36,8 @@ export const FeedView = (props: FeedProps) => { const topReactions = createMemo(() => sortBy(reactions(), byCreated)) + const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) + // const expectingFocus = createMemo(() => { // // 1 co-author notifications needs // // TODO: list of articles where you are co-author @@ -53,13 +51,15 @@ export const FeedView = (props: FeedProps) => { // return [] // }) - // eslint-disable-next-line unicorn/consistent-function-scoping - const loadMore = () => { - // const limit = props.limit || 50 - // const offset = props.offset || 0 - // FIXME - loadRecentArticles({ limit: 50, offset: 0 }) + const loadMore = async () => { + const { hasMore } = await loadRecentArticles({ limit: FEED_PAGE_SIZE, offset: sortedArticles().length }) + setIsLoadMoreButtonVisible(hasMore) } + + onMount(() => { + loadMore() + }) + return ( <>
@@ -113,10 +113,6 @@ export const FeedView = (props: FeedProps) => { {(article) => } - -

- -

- -

- -

+ +

+ +

+
) diff --git a/src/components/Views/Home.tsx b/src/components/Views/Home.tsx index 418edf52..77509a43 100644 --- a/src/components/Views/Home.tsx +++ b/src/components/Views/Home.tsx @@ -1,12 +1,12 @@ -import { createMemo, For, onMount, Show } from 'solid-js' +import { createMemo, createSignal, For, onMount, Show } from 'solid-js' import Banner from '../Discours/Banner' import { NavTopics } from '../Nav/Topics' import { Row5 } from '../Feed/Row5' -import Row3 from '../Feed/Row3' -import Row2 from '../Feed/Row2' -import Row1 from '../Feed/Row1' +import { Row3 } from '../Feed/Row3' +import { Row2 } from '../Feed/Row2' +import { Row1 } from '../Feed/Row1' import Hero from '../Discours/Hero' -import Beside from '../Feed/Beside' +import { Beside } from '../Feed/Beside' import RowShort from '../Feed/RowShort' import Slider from '../Feed/Slider' import Group from '../Feed/Group' @@ -24,6 +24,7 @@ import { import { useTopAuthorsStore } from '../../stores/zine/topAuthors' import { locale } from '../../stores/ui' import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll' +import { splitToPages } from '../../utils/splitToPages' const log = getLogger('home view') @@ -31,7 +32,8 @@ type HomeProps = { randomTopics: Topic[] recentPublishedArticles: Shout[] } -const PRERENDERED_ARTICLES_COUNT = 5 + +export const PRERENDERED_ARTICLES_COUNT = 5 const CLIENT_LOAD_ARTICLES_COUNT = 29 const LOAD_MORE_PAGE_SIZE = 16 // Row1 + Row3 + Row2 + Beside (3 + 1) + Row1 + Row 2 + Row3 @@ -49,14 +51,20 @@ export const HomeView = (props: HomeProps) => { const { randomTopics, topTopics } = useTopicsStore({ randomTopics: props.randomTopics }) + const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const { topAuthors } = useTopAuthorsStore() - onMount(() => { + onMount(async () => { loadTopArticles() loadTopMonthArticles() if (sortedArticles().length < PRERENDERED_ARTICLES_COUNT + CLIENT_LOAD_ARTICLES_COUNT) { - loadPublishedArticles({ limit: CLIENT_LOAD_ARTICLES_COUNT, offset: sortedArticles().length }) + const { hasMore } = await loadPublishedArticles({ + limit: CLIENT_LOAD_ARTICLES_COUNT, + offset: sortedArticles().length + }) + + setIsLoadMoreButtonVisible(hasMore) } }) @@ -85,22 +93,23 @@ export const HomeView = (props: HomeProps) => { const loadMore = async () => { saveScrollPosition() - await loadPublishedArticles({ limit: LOAD_MORE_PAGE_SIZE, offset: sortedArticles().length }) + + const { hasMore } = await loadPublishedArticles({ + limit: LOAD_MORE_PAGE_SIZE, + offset: sortedArticles().length + }) + setIsLoadMoreButtonVisible(hasMore) + restoreScrollPosition() } - const pages = createMemo(() => { - return sortedArticles() - .slice(PRERENDERED_ARTICLES_COUNT + CLIENT_LOAD_ARTICLES_COUNT) - .reduce((acc, article, index) => { - if (index % LOAD_MORE_PAGE_SIZE === 0) { - acc.push([]) - } - - acc[acc.length - 1].push(article) - return acc - }, [] as Shout[][]) - }) + const pages = createMemo(() => + splitToPages( + sortedArticles(), + PRERENDERED_ARTICLES_COUNT + CLIENT_LOAD_ARTICLES_COUNT, + LOAD_MORE_PAGE_SIZE + ) + ) return ( 0}> @@ -173,11 +182,13 @@ export const HomeView = (props: HomeProps) => { )} -

- -

+ +

+ +

+
) } diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index a0784b55..8e96ea6f 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -1,16 +1,18 @@ -import { For, Show, createMemo } from 'solid-js' +import { For, Show, createMemo, onMount, createSignal } from 'solid-js' import type { Shout, Topic } from '../../graphql/types.gen' -import Row3 from '../Feed/Row3' -import Row2 from '../Feed/Row2' -import Beside from '../Feed/Beside' +import { Row3 } from '../Feed/Row3' +import { Row2 } from '../Feed/Row2' +import { Beside } from '../Feed/Beside' import { ArticleCard } from '../Feed/Card' import '../../styles/Topic.scss' import { FullTopic } from '../Topic/Full' import { t } from '../../utils/intl' import { useRouter } from '../../stores/router' import { useTopicsStore } from '../../stores/zine/topics' -import { useArticlesStore } from '../../stores/zine/articles' +import { loadPublishedArticles, useArticlesStore } from '../../stores/zine/articles' import { useAuthorsStore } from '../../stores/zine/authors' +import { restoreScrollPosition, saveScrollPosition } from '../../utils/scroll' +import { splitToPages } from '../../utils/splitToPages' type TopicsPageSearchParams = { by: 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'commented' @@ -22,9 +24,14 @@ interface TopicProps { topicSlug: string } +export const PRERENDERED_ARTICLES_COUNT = 21 +const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3 + export const TopicView = (props: TopicProps) => { const { searchParams, changeSearchParam } = useRouter() + const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) + const { sortedArticles } = useArticlesStore({ sortedArticles: props.topicArticles }) const { topicEntities } = useTopicsStore({ topics: [props.topic] }) @@ -32,6 +39,24 @@ export const TopicView = (props: TopicProps) => { const topic = createMemo(() => topicEntities()[props.topicSlug]) + const loadMore = async () => { + saveScrollPosition() + + const { hasMore } = await loadPublishedArticles({ + limit: LOAD_MORE_PAGE_SIZE, + offset: sortedArticles().length + }) + setIsLoadMoreButtonVisible(hasMore) + + restoreScrollPosition() + } + + onMount(async () => { + if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) { + loadMore() + } + }) + const title = createMemo(() => { const m = searchParams().by if (m === 'viewed') return t('Top viewed') @@ -40,6 +65,10 @@ export const TopicView = (props: TopicProps) => { return t('Top recent') }) + const pages = createMemo(() => + splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE) + ) + return (
@@ -110,6 +139,24 @@ export const TopicView = (props: TopicProps) => { + + + {(page) => ( + <> + + + + + )} + + + +

+ +

+
diff --git a/src/components/types.ts b/src/components/types.ts index 0b2fca98..870943e1 100644 --- a/src/components/types.ts +++ b/src/components/types.ts @@ -8,7 +8,6 @@ export type PageProps = { authorArticles?: Shout[] topicArticles?: Shout[] homeArticles?: Shout[] - feedArticles?: Shout[] author?: Author allAuthors?: Author[] topic?: Topic diff --git a/src/pages/author/[slug]/index.astro b/src/pages/author/[slug]/index.astro index 7ad13be2..50e29aa4 100644 --- a/src/pages/author/[slug]/index.astro +++ b/src/pages/author/[slug]/index.astro @@ -3,9 +3,10 @@ import { Root } from '../../../components/Root' import Zine from '../../../layouts/zine.astro' import { apiClient } from '../../../utils/apiClient' import { initRouter } from '../../../stores/router' +import { PRERENDERED_ARTICLES_COUNT } from '../../../components/Views/Author' const slug = Astro.params.slug.toString() -const articles = await apiClient.getArticlesForAuthors({ authorSlugs: [slug], limit: 50 }) +const articles = await apiClient.getArticlesForAuthors({ authorSlugs: [slug], limit: PRERENDERED_ARTICLES_COUNT }) const author = articles[0].authors.find((a) => a.slug === slug) const { pathname, search } = Astro.url diff --git a/src/pages/feed/index.astro b/src/pages/feed/index.astro index 93c40a9c..e9063068 100644 --- a/src/pages/feed/index.astro +++ b/src/pages/feed/index.astro @@ -1,16 +1,12 @@ --- import { Root } from '../../components/Root' import Zine from '../../layouts/zine.astro' -import { apiClient } from '../../utils/apiClient' - import { initRouter } from '../../stores/router' const { pathname, search } = Astro.url initRouter(pathname, search) - -const articles = await apiClient.getRecentArticles({ limit: 50 }) --- - + diff --git a/src/pages/index.astro b/src/pages/index.astro index e03b076c..9bbde9a4 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -3,14 +3,14 @@ import Zine from '../layouts/zine.astro' import { Root } from '../components/Root' import { apiClient } from '../utils/apiClient' import { initRouter } from '../stores/router' +import { PRERENDERED_ARTICLES_COUNT } from '../components/Views/Home' const randomTopics = await apiClient.getRandomTopics({ amount: 12 }) -const articles = await apiClient.getRecentPublishedArticles({ limit: 5 }) +const articles = await apiClient.getRecentPublishedArticles({ limit: PRERENDERED_ARTICLES_COUNT }) const { pathname, search } = Astro.url initRouter(pathname, search) - Astro.response.headers.set('Cache-Control', 's-maxage=1, stale-while-revalidate') --- diff --git a/src/pages/topic/[slug].astro b/src/pages/topic/[slug].astro index 98134a4b..91ebde65 100644 --- a/src/pages/topic/[slug].astro +++ b/src/pages/topic/[slug].astro @@ -2,9 +2,10 @@ import { Root } from '../../components/Root' import Zine from '../../layouts/zine.astro' import { apiClient } from '../../utils/apiClient' +import { PRERENDERED_ARTICLES_COUNT } from '../../components/Views/Topic' const slug = Astro.params.slug?.toString() || '' -const articles = await apiClient.getArticlesForTopics({ topicSlugs: [slug], limit: 50 }) +const articles = await apiClient.getArticlesForTopics({ topicSlugs: [slug], limit: PRERENDERED_ARTICLES_COUNT }) const topic = articles[0].topics.find(({ slug: topicSlug }) => topicSlug === slug) import { initRouter } from '../../stores/router' diff --git a/src/stores/zine/articles.ts b/src/stores/zine/articles.ts index fa2ca139..ee746f1a 100644 --- a/src/stores/zine/articles.ts +++ b/src/stores/zine/articles.ts @@ -127,40 +127,109 @@ const addSortedArticles = (articles: Shout[]) => { setSortedArticles((prevSortedArticles) => [...prevSortedArticles, ...articles]) } +export const loadFeed = async ({ + limit, + offset +}: { + limit: number + offset?: number +}): Promise<{ hasMore: boolean }> => { + // TODO: load actual feed + return await loadRecentArticles({ limit, offset }) +} + export const loadRecentArticles = async ({ limit, offset }: { - limit?: number + limit: number offset?: number -}): Promise => { - const newArticles = await apiClient.getRecentArticles({ limit, offset }) +}): Promise<{ hasMore: boolean }> => { + const newArticles = await apiClient.getRecentArticles({ limit: limit + 1, offset }) + const hasMore = newArticles.length === limit + 1 + + if (hasMore) { + newArticles.splice(-1) + } + addArticles(newArticles) addSortedArticles(newArticles) + + return { hasMore } } export const loadPublishedArticles = async ({ limit, - offset + offset = 0 }: { - limit?: number + limit: number offset?: number -}): Promise => { - const newArticles = await apiClient.getPublishedArticles({ limit, offset }) +}): Promise<{ hasMore: boolean }> => { + const newArticles = await apiClient.getPublishedArticles({ limit: limit + 1, offset }) + const hasMore = newArticles.length === limit + 1 + + if (hasMore) { + newArticles.splice(-1) + } + addArticles(newArticles) addSortedArticles(newArticles) + + return { hasMore } } -export const loadArticlesForAuthors = async ({ authorSlugs }: { authorSlugs: string[] }): Promise => { - const articles = await apiClient.getArticlesForAuthors({ authorSlugs, limit: 50 }) - addArticles(articles) - setSortedArticles(articles) +export const loadAuthorArticles = async ({ + authorSlug, + limit, + offset = 0 +}: { + authorSlug: string + limit: number + offset?: number +}): Promise<{ hasMore: boolean }> => { + const newArticles = await apiClient.getArticlesForAuthors({ + authorSlugs: [authorSlug], + limit: limit + 1, + offset + }) + + const hasMore = newArticles.length === limit + 1 + + if (hasMore) { + newArticles.splice(-1) + } + + addArticles(newArticles) + addSortedArticles(newArticles) + + return { hasMore } } -export const loadArticlesForTopics = async ({ topicSlugs }: { topicSlugs: string[] }): Promise => { - const articles = await apiClient.getArticlesForTopics({ topicSlugs, limit: 50 }) - addArticles(articles) - setSortedArticles(articles) +export const loadTopicArticles = async ({ + topicSlug, + limit, + offset +}: { + topicSlug: string + limit: number + offset: number +}): Promise<{ hasMore: boolean }> => { + const newArticles = await apiClient.getArticlesForTopics({ + topicSlugs: [topicSlug], + limit: limit + 1, + offset + }) + + const hasMore = newArticles.length === limit + 1 + + if (hasMore) { + newArticles.splice(-1) + } + + addArticles(newArticles) + addSortedArticles(newArticles) + + return { hasMore } } export const resetSortedArticles = () => { diff --git a/src/stores/zine/authors.ts b/src/stores/zine/authors.ts index 072b172c..93aa272b 100644 --- a/src/stores/zine/authors.ts +++ b/src/stores/zine/authors.ts @@ -1,6 +1,5 @@ import { apiClient } from '../../utils/apiClient' import type { Author } from '../../graphql/types.gen' -import { byCreated, byStat, byTopicStatDesc } from '../../utils/sortby' import { getLogger } from '../../utils/logger' import { createSignal } from 'solid-js' diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts index abcba96e..4f420bee 100644 --- a/src/utils/apiClient.ts +++ b/src/utils/apiClient.ts @@ -184,7 +184,7 @@ export const apiClient = { }, getArticlesForTopics: async ({ topicSlugs, - limit = FEED_SIZE, + limit, offset = 0 }: { topicSlugs: string[] @@ -207,7 +207,7 @@ export const apiClient = { }, getArticlesForAuthors: async ({ authorSlugs, - limit = FEED_SIZE, + limit, offset = 0 }: { authorSlugs: string[] diff --git a/src/utils/splitToPages.ts b/src/utils/splitToPages.ts new file mode 100644 index 00000000..c26d1913 --- /dev/null +++ b/src/utils/splitToPages.ts @@ -0,0 +1,10 @@ +export function splitToPages(arr: T[], startIndex: number, pageSize: number): T[][] { + return arr.slice(startIndex).reduce((acc, article, index) => { + if (index % pageSize === 0) { + acc.push([]) + } + + acc[acc.length - 1].push(article) + return acc + }, [] as T[][]) +}