From 305bd23f9f40e005972360ed1de2a4421b5715c5 Mon Sep 17 00:00:00 2001 From: Untone Date: Fri, 28 Jun 2024 10:47:38 +0300 Subject: [PATCH] home-tops --- app.config.ts | 1 + biome.json | 6 ++- .../Feed/ArticleCard/ArticleCard.tsx | 8 ++-- src/components/Views/Home.tsx | 11 +++-- .../_shared/SolidSwiper/ArticleCardSwiper.tsx | 9 ++-- src/routes/(home).tsx | 48 +++++++++++-------- src/routes/[...slug].tsx | 5 +- src/utils/ga.ts | 2 + src/utils/sortby.ts | 6 ++- 9 files changed, 59 insertions(+), 37 deletions(-) diff --git a/app.config.ts b/app.config.ts index 9832fea9..5c758d8d 100644 --- a/app.config.ts +++ b/app.config.ts @@ -4,6 +4,7 @@ import sassDts from 'vite-plugin-sass-dts' const isVercel = Boolean(process?.env.VERCEL) const isBun = Boolean(process.env.BUN) + export default defineConfig({ ssr: true, server: { diff --git a/biome.json b/biome.json index cf0b9ae5..bb722565 100644 --- a/biome.json +++ b/biome.json @@ -6,11 +6,13 @@ }, "vcs": { "defaultBranch": "dev", - "useIgnoreFile": true + "useIgnoreFile": true, + "enabled": true, + "clientKind": "git" }, "organizeImports": { "enabled": true, - "ignore": ["./api", "./gen"] + "ignore": ["./gen"] }, "formatter": { "indentStyle": "space", diff --git a/src/components/Feed/ArticleCard/ArticleCard.tsx b/src/components/Feed/ArticleCard/ArticleCard.tsx index 4cce20bf..930e1a31 100644 --- a/src/components/Feed/ArticleCard/ArticleCard.tsx +++ b/src/components/Feed/ArticleCard/ArticleCard.tsx @@ -62,8 +62,8 @@ const getTitleAndSubtitle = ( title: string subtitle: string } => { - let title = article.title - let subtitle: string = article.subtitle || '' + let title = article?.title || '' + let subtitle: string = article?.subtitle || '' if (!subtitle) { let titleParts = article.title?.split('. ') || [] @@ -220,7 +220,7 @@ export const ArticleCard = (props: ArticleCardProps) => { [styles.shoutCardTitlesContainerFeedMode]: props.settings?.isFeedMode })} > - +
@@ -229,7 +229,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
- +
diff --git a/src/components/Views/Home.tsx b/src/components/Views/Home.tsx index ffb8272c..a1f80367 100644 --- a/src/components/Views/Home.tsx +++ b/src/components/Views/Home.tsx @@ -3,7 +3,7 @@ import { For, Show, createEffect, createMemo, createSignal, on } from 'solid-js' import { useAuthors } from '~/context/authors' import { useLocalize } from '../../context/localize' import { useTopics } from '../../context/topics' -import { Shout, Topic } from '../../graphql/schema/core.gen' +import { Author, Shout, Topic } from '../../graphql/schema/core.gen' import { capitalize } from '../../utils/capitalize' import { splitToPages } from '../../utils/splitToPages' import Banner from '../Discours/Banner' @@ -38,7 +38,7 @@ export interface HomeViewProps { export const HomeView = (props: HomeViewProps) => { const { t } = useLocalize() - const { topAuthors } = useAuthors() + const { topAuthors, addAuthors } = useAuthors() const { topTopics, randomTopic } = useTopics() const [randomTopicArticles, setRandomTopicArticles] = createSignal([]) createEffect( @@ -53,6 +53,9 @@ export const HomeView = (props: HomeViewProps) => { }) const shouts = await shoutsByTopicLoader() setRandomTopicArticles(shouts || []) + shouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) + props.featuredShouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) + props.topRatedShouts?.forEach((s: Shout) => addAuthors((s?.authors || []) as Author[])) } }, { defer: true } @@ -84,7 +87,7 @@ export const HomeView = (props: HomeViewProps) => { @@ -96,7 +99,7 @@ export const HomeView = (props: HomeViewProps) => { {t('Top commented')}} nodate={true} /> diff --git a/src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx b/src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx index 7b5570a3..ebc29cd9 100644 --- a/src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx +++ b/src/components/_shared/SolidSwiper/ArticleCardSwiper.tsx @@ -23,7 +23,8 @@ export const ArticleCardSwiper = (props: Props) => { let mainSwipeRef: SwiperRef | null onMount(async () => { - if (props.slides.length > 1) { + if (props.slides?.length > 1) { + console.debug(props.slides) const { register } = await import('swiper/element/bundle') register() SwiperCore.use([Pagination, Navigation, Manipulation]) @@ -34,16 +35,16 @@ export const ArticleCardSwiper = (props: Props) => {
1, + [styles.Swiper]: props.slides?.length > 1, [styles.articleMode]: true, - [styles.ArticleCardSwiper]: props.slides.length > 1 + [styles.ArticleCardSwiper]: props.slides?.length > 1 })} >

{props.title}

- 0}> + 0}> }> }>
diff --git a/src/routes/(home).tsx b/src/routes/(home).tsx index d840b53a..2639e817 100644 --- a/src/routes/(home).tsx +++ b/src/routes/(home).tsx @@ -1,7 +1,9 @@ import { type RouteDefinition, type RouteSectionProps, createAsync } from '@solidjs/router' import { Show, Suspense, createEffect, createSignal, on, onMount } from 'solid-js' +import { LoadShoutsOptions } from '~/graphql/schema/core.gen' import { loadShouts } from '~/lib/api' import { restoreScrollPosition, saveScrollPosition } from '~/utils/scroll' +import { byStat } from '~/utils/sortby' import { HomeView, HomeViewProps } from '../components/Views/Home' import { Loading } from '../components/_shared/Loading' import { PageLayout } from '../components/_shared/PageLayout' @@ -11,32 +13,33 @@ import { ReactionsProvider } from '../context/reactions' export const SHOUTS_PER_PAGE = 20 const fetchHomeTopData = async () => { - const limit = 20 - const topCommentedLoader = loadShouts({ filters: { featured: true }, - limit + order_by: 'comments_stat', + limit: 10 }) - const topMonthLoader = loadShouts({ - filters: { featured: true }, - limit - }) - - const topViewedLoader = loadShouts({ - filters: { featured: true }, - limit - }) + const daysago = Date.now() - 30 * 24 * 60 * 60 * 1000 + const after = Math.floor(daysago / 1000) + const options: LoadShoutsOptions = { + filters: { + featured: true, + after + }, + order_by: 'likes_stat', + limit: 10 + } + const topMonthLoader = loadShouts({ ...options }) const topRatedLoader = loadShouts({ filters: { featured: true }, - limit + order_by: 'likes_stat', + limit: 10 }) return { - topCommentedShouts: await topCommentedLoader(), - topMonthShouts: await topMonthLoader(), topRatedShouts: await topRatedLoader(), - topViewedShouts: await topViewedLoader() + topMonthShouts: await topMonthLoader(), + topCommentedShouts: await topCommentedLoader() } as Partial } @@ -69,12 +72,19 @@ export default function HomePage(props: RouteSectionProps) { // async ssr-friendly router-level cached data source const data = createAsync(async (prev?: HomeViewProps) => { const featuredShoutsLoader = featuredLoader(featuredOffset()) - const featuredShouts = await featuredShoutsLoader() - return { + const featuredShouts = [ + ...(prev?.featuredShouts || []), + ...((await featuredShoutsLoader()) || props.data?.featuredShouts || []) + ] + const sortFn = byStat('viewed') + const topViewedShouts = featuredShouts?.sort(sortFn) || [] + const result = { ...prev, ...props.data, - featuredShouts: featuredShouts || prev?.featuredShouts || props.data?.featuredShouts + topViewedShouts, + featuredShouts } + return result }) const [canLoadMoreFeatured, setCanLoadMoreFeatured] = createSignal(false) diff --git a/src/routes/[...slug].tsx b/src/routes/[...slug].tsx index 331f8312..bee9c52e 100644 --- a/src/routes/[...slug].tsx +++ b/src/routes/[...slug].tsx @@ -28,7 +28,7 @@ export const ArticlePage = (props: RouteSectionProps<{ article: Shout }>) => { () => `${article()?.authors?.[0]?.name || t('Discours')}: ${article()?.title || ''}` ) onMount(async () => { - if(gaIdentity) { + if (gaIdentity) { try { console.info('[routes.slug] mounted, connecting ga...') await loadGAScript(gaIdentity) @@ -44,10 +44,11 @@ export const ArticlePage = (props: RouteSectionProps<{ article: Shout }>) => { // wrapped by the returned tracking function is notified of a change` createReaction(() => { if (article()) { + console.debug('[routes.slug] article signal changed once') window.gtag?.('event', 'page_view', { page_title: article()?.title, page_location: window.location.href, - page_path: window.location.pathname, + page_path: window.location.pathname }) } }) diff --git a/src/utils/ga.ts b/src/utils/ga.ts index fc8c0968..c5ca7c4b 100644 --- a/src/utils/ga.ts +++ b/src/utils/ga.ts @@ -19,10 +19,12 @@ export const loadGAScript = (id: string) => { export const initGA = (id: string) => { const w = window as Window if (w) { + // @ts-ignore // biome-ignore lint/suspicious/noExplicitAny: ga-script w.dataLayer = (w.dataLayer as any) || [] // biome-ignore lint/suspicious/noExplicitAny: ga-script function gtag(...args: any[]) { + // @ts-ignore w.dataLayer.push(args) } gtag('js', new Date()) diff --git a/src/utils/sortby.ts b/src/utils/sortby.ts index bd048278..61ef9676 100644 --- a/src/utils/sortby.ts +++ b/src/utils/sortby.ts @@ -1,4 +1,4 @@ -import type { Author, Reaction, Shout, Topic, TopicStat } from '../graphql/schema/core.gen' +import type { Author, Maybe, Reaction, Shout, Topic, TopicStat } from '../graphql/schema/core.gen' // biome-ignore lint/suspicious/noExplicitAny: sort by first char export const byFirstChar = (a: { name?: any; title?: any }, b: { name?: any; title?: any }) => @@ -26,8 +26,10 @@ export const byLength = ( return 0 } +export type SomeStat = { [x: string]: Maybe } | undefined | null + export const byStat = (metric: string) => { - return (a: { stat: { [x: string]: number } }, b: { stat: { [x: string]: number } }) => { + return (a: { stat?: SomeStat }, b: { stat?: SomeStat }) => { const aStat = a.stat?.[metric] ?? 0 const bStat = b.stat?.[metric] ?? 0 return aStat - bStat