diff --git a/.github/workflows/node-ci.yml b/.github/workflows/node-ci.yml index 2d2d4bc8..1220b122 100644 --- a/.github/workflows/node-ci.yml +++ b/.github/workflows/node-ci.yml @@ -16,7 +16,7 @@ jobs: run: npm run typecheck - name: Lint with Biome - run: npx biome ci . + run: npm run check:code - name: Lint styles run: npm run lint:styles diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 651ee47d..870d4e5c 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -1,169 +1,169 @@ -import type { Author, Reaction, Shout, Topic } from "../../../graphql/schema/core.gen"; +import type { Author, Reaction, Shout, Topic } from '../../../graphql/schema/core.gen' -import { getPagePath } from "@nanostores/router"; -import { Meta, Title } from "@solidjs/meta"; -import { clsx } from "clsx"; -import { For, Match, Show, Switch, createEffect, createMemo, createSignal, onMount } from "solid-js"; +import { getPagePath } from '@nanostores/router' +import { Meta, Title } from '@solidjs/meta' +import { clsx } from 'clsx' +import { For, Match, Show, Switch, createEffect, createMemo, createSignal, onMount } from 'solid-js' -import { useFollowing } from "../../../context/following"; -import { useLocalize } from "../../../context/localize"; -import { useSession } from "../../../context/session"; -import { apiClient } from "../../../graphql/client/core"; -import { router, useRouter } from "../../../stores/router"; -import { loadShouts, useArticlesStore } from "../../../stores/zine/articles"; -import { loadAuthor, useAuthorsStore } from "../../../stores/zine/authors"; -import { getImageUrl } from "../../../utils/getImageUrl"; -import { getDescription } from "../../../utils/meta"; -import { restoreScrollPosition, saveScrollPosition } from "../../../utils/scroll"; -import { splitToPages } from "../../../utils/splitToPages"; -import { Comment } from "../../Article/Comment"; -import { AuthorCard } from "../../Author/AuthorCard"; -import { AuthorShoutsRating } from "../../Author/AuthorShoutsRating"; -import { Row1 } from "../../Feed/Row1"; -import { Row2 } from "../../Feed/Row2"; -import { Row3 } from "../../Feed/Row3"; -import { Loading } from "../../_shared/Loading"; +import { useFollowing } from '../../../context/following' +import { useLocalize } from '../../../context/localize' +import { useSession } from '../../../context/session' +import { apiClient } from '../../../graphql/client/core' +import { router, useRouter } from '../../../stores/router' +import { loadShouts, useArticlesStore } from '../../../stores/zine/articles' +import { loadAuthor, useAuthorsStore } from '../../../stores/zine/authors' +import { getImageUrl } from '../../../utils/getImageUrl' +import { getDescription } from '../../../utils/meta' +import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll' +import { splitToPages } from '../../../utils/splitToPages' +import { Comment } from '../../Article/Comment' +import { AuthorCard } from '../../Author/AuthorCard' +import { AuthorShoutsRating } from '../../Author/AuthorShoutsRating' +import { Row1 } from '../../Feed/Row1' +import { Row2 } from '../../Feed/Row2' +import { Row3 } from '../../Feed/Row3' +import { Loading } from '../../_shared/Loading' -import { MODALS, hideModal } from "../../../stores/ui"; -import { byCreated } from "../../../utils/sortby"; -import stylesArticle from "../../Article/Article.module.scss"; -import styles from "./Author.module.scss"; +import { MODALS, hideModal } from '../../../stores/ui' +import { byCreated } from '../../../utils/sortby' +import stylesArticle from '../../Article/Article.module.scss' +import styles from './Author.module.scss' type Props = { - authorSlug: string; - shouts?: Shout[]; - author?: Author; -}; -export const PRERENDERED_ARTICLES_COUNT = 12; -const LOAD_MORE_PAGE_SIZE = 9; + authorSlug: string + shouts?: Shout[] + author?: Author +} +export const PRERENDERED_ARTICLES_COUNT = 12 +const LOAD_MORE_PAGE_SIZE = 9 export const AuthorView = (props: Props) => { - const { t } = useLocalize(); - const { subscriptions, followers: myFollowers, loadSubscriptions } = useFollowing(); - const { session } = useSession(); - const { sortedArticles } = useArticlesStore({ shouts: props.shouts }); - const { authorEntities } = useAuthorsStore({ authors: [props.author] }); - const { page: getPage, searchParams } = useRouter(); - const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false); - const [isBioExpanded, setIsBioExpanded] = createSignal(false); - const [author, setAuthor] = createSignal(); - const [followers, setFollowers] = createSignal([]); - const [following, setFollowing] = createSignal>([]); // flat AuthorFollowsResult - const [showExpandBioControl, setShowExpandBioControl] = createSignal(false); - const [commented, setCommented] = createSignal(); - const modal = MODALS[searchParams().m]; + const { t } = useLocalize() + const { subscriptions, followers: myFollowers, loadSubscriptions } = useFollowing() + const { session } = useSession() + const { sortedArticles } = useArticlesStore({ shouts: props.shouts }) + const { authorEntities } = useAuthorsStore({ authors: [props.author] }) + const { page: getPage, searchParams } = useRouter() + const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) + const [isBioExpanded, setIsBioExpanded] = createSignal(false) + const [author, setAuthor] = createSignal() + const [followers, setFollowers] = createSignal([]) + const [following, setFollowing] = createSignal>([]) // flat AuthorFollowsResult + const [showExpandBioControl, setShowExpandBioControl] = createSignal(false) + const [commented, setCommented] = createSignal() + const modal = MODALS[searchParams().m] // current author createEffect(async () => { - await loadAuthor({ slug: props.authorSlug }); + await loadAuthor({ slug: props.authorSlug }) }) - createEffect( () => { + createEffect(() => { if (props.authorSlug && session()?.user?.app_data?.profile?.slug === props.authorSlug) { - console.info("my own profile"); - const { profile, authors, topics } = session().user.app_data; - setFollowers(myFollowers); - setAuthor(profile); - setFollowing([...authors, ...topics]); + console.info('my own profile') + const { profile, authors, topics } = session().user.app_data + setFollowers(myFollowers) + setAuthor(profile) + setFollowing([...authors, ...topics]) } else { try { - const a = authorEntities()[props.authorSlug]; - setAuthor(a); + const a = authorEntities()[props.authorSlug] + setAuthor(a) // TODO: add following data retrieval - console.debug("[Author] expecting following data fetched"); + console.debug('[Author] expecting following data fetched') } catch (error) { - console.debug(error); + console.debug(error) } } - }); + }) createEffect(async () => { if (author()?.id && !author().stat) { - const a = await loadAuthor({ slug: "", author_id: author().id }); - console.debug("[AuthorView] loaded author:", a); + const a = await loadAuthor({ slug: '', author_id: author().id }) + console.debug('[AuthorView] loaded author:', a) } - }); + }) - const bioContainerRef: { current: HTMLDivElement } = { current: null }; - const bioWrapperRef: { current: HTMLDivElement } = { current: null }; + const bioContainerRef: { current: HTMLDivElement } = { current: null } + const bioWrapperRef: { current: HTMLDivElement } = { current: null } const fetchData = async (slug) => { try { const [subscriptionsResult, followersResult] = await Promise.all([ apiClient.getAuthorFollows({ slug }), apiClient.getAuthorFollowers({ slug }), - ]); + ]) - const { authors, topics } = subscriptionsResult; - setFollowing([...(authors || []), ...(topics || [])]); - setFollowers(followersResult || []); + const { authors, topics } = subscriptionsResult + setFollowing([...(authors || []), ...(topics || [])]) + setFollowers(followersResult || []) - console.info("[components.Author] following data loaded"); + console.info('[components.Author] following data loaded') } catch (error) { - console.error("[components.Author] fetch error", error); + console.error('[components.Author] fetch error', error) } - }; + } const checkBioHeight = () => { if (bioContainerRef.current) { - setShowExpandBioControl(bioContainerRef.current.offsetHeight > bioWrapperRef.current.offsetHeight); + setShowExpandBioControl(bioContainerRef.current.offsetHeight > bioWrapperRef.current.offsetHeight) } - }; + } onMount(() => { - fetchData(props.authorSlug); + fetchData(props.authorSlug) if (!modal) { - hideModal(); + hideModal() } - }); + }) const loadMore = async () => { - saveScrollPosition(); + saveScrollPosition() const { hasMore } = await loadShouts({ filters: { author: props.authorSlug }, limit: LOAD_MORE_PAGE_SIZE, offset: sortedArticles().length, - }); - setIsLoadMoreButtonVisible(hasMore); - restoreScrollPosition(); - }; + }) + setIsLoadMoreButtonVisible(hasMore) + restoreScrollPosition() + } onMount(() => { - checkBioHeight(); + checkBioHeight() // pagination if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) { - loadMore(); - loadSubscriptions(); + loadMore() + loadSubscriptions() } - }); + }) const pages = createMemo(() => splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE), - ); + ) const fetchComments = async (commenter: Author) => { const data = await apiClient.getReactionsBy({ by: { comment: false, created_by: commenter.id }, - }); - setCommented(data); - }; + }) + setCommented(data) + } createEffect(() => { if (author()) { - fetchComments(author()); + fetchComments(author()) } - }); + }) const ogImage = createMemo(() => author()?.pic ? getImageUrl(author()?.pic, { width: 1200 }) - : getImageUrl("production/image/logo_image.png"), - ); - const description = createMemo(() => getDescription(author()?.bio)); + : getImageUrl('production/image/logo_image.png'), + ) + const description = createMemo(() => getDescription(author()?.bio)) const handleDeleteComment = (id: number) => { - setCommented((prev) => prev.filter((comment) => comment.id !== id)); - }; + setCommented((prev) => prev.filter((comment) => comment.id !== id)) + } return (
@@ -185,20 +185,20 @@ export const AuthorView = (props: Props) => {
-
+
-
+
- {t("All posts rating")} + {t('All posts rating')}
@@ -250,7 +250,7 @@ export const AuthorView = (props: Props) => {
- +
@@ -264,17 +264,17 @@ export const AuthorView = (props: Props) => {
- +
@@ -294,7 +294,7 @@ export const AuthorView = (props: Props) => {
- + @@ -332,12 +332,12 @@ export const AuthorView = (props: Props) => {

- ); -}; + ) +} diff --git a/src/components/_shared/SolidSwiper/ImageSwiper.tsx b/src/components/_shared/SolidSwiper/ImageSwiper.tsx index 9653b449..888a23c3 100644 --- a/src/components/_shared/SolidSwiper/ImageSwiper.tsx +++ b/src/components/_shared/SolidSwiper/ImageSwiper.tsx @@ -53,12 +53,11 @@ export const ImageSwiper = (props: Props) => { register() SwiperCore.use([Pagination, Navigation, Manipulation]) while (!mainSwipeRef.current || !mainSwipeRef.current.swiper) { - await new Promise(resolve => setTimeout(resolve, 10)); // wait 10 ms + await new Promise((resolve) => setTimeout(resolve, 10)) // wait 10 ms } - mainSwipeRef.current.swiper.on('slideChange', handleSlideChange); + mainSwipeRef.current.swiper.on('slideChange', handleSlideChange) }) - onMount(() => { const updateDirection = () => { const width = window.innerWidth diff --git a/src/stores/zine/authors.ts b/src/stores/zine/authors.ts index 33861246..2253b84e 100644 --- a/src/stores/zine/authors.ts +++ b/src/stores/zine/authors.ts @@ -1,5 +1,5 @@ import { createLazyMemo } from '@solid-primitives/memo' -import { createEffect, createSignal } from "solid-js"; +import { createEffect, createSignal } from 'solid-js' import { apiClient } from '../../graphql/client/core' import { Author, QueryLoad_Authors_ByArgs } from '../../graphql/schema/core.gen'