From b84e7f43f7aea6727466c21100a53243035cbe72 Mon Sep 17 00:00:00 2001 From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com> Date: Mon, 25 Mar 2024 16:07:14 +0300 Subject: [PATCH 01/36] Fix reload page after foute from profile to another profile (#430) --- src/components/Views/Author/Author.tsx | 10 ++++------ src/pages/author.page.tsx | 8 +------- src/utils/getImageUrl.ts | 20 ++++++++++---------- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index a21cebcc..c7515382 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -29,8 +29,6 @@ import stylesArticle from '../../Article/Article.module.scss' import styles from './Author.module.scss' type Props = { - shouts: Shout[] - author: Author authorSlug: string } export const PRERENDERED_ARTICLES_COUNT = 12 @@ -39,8 +37,8 @@ const LOAD_MORE_PAGE_SIZE = 9 export const AuthorView = (props: Props) => { const { t } = useLocalize() const { loadSubscriptions } = useFollowing() - const { sortedArticles } = useArticlesStore({ shouts: props.shouts }) - const { authorEntities } = useAuthorsStore({ authors: [props.author] }) + const { sortedArticles } = useArticlesStore() + const { authorEntities } = useAuthorsStore() const { page: getPage, searchParams } = useRouter() const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) const [isBioExpanded, setIsBioExpanded] = createSignal(false) @@ -200,10 +198,10 @@ export const AuthorView = (props: Props) => {
- +
{t('All posts rating')} - +
diff --git a/src/pages/author.page.tsx b/src/pages/author.page.tsx index 39c4dc28..e23f92d3 100644 --- a/src/pages/author.page.tsx +++ b/src/pages/author.page.tsx @@ -56,17 +56,11 @@ export const AuthorPage = (props: PageProps) => { onCleanup(() => resetSortedArticles()) - const usePrerenderedData = props.author?.slug === slug() - return ( }> - + diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index 7b8b56dc..bc3c9073 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -15,17 +15,17 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { - if (!src.includes('discours.io') && src.includes('http')) { - return src - } - const filename = src.toLowerCase().split('/').pop() - const ext = filename.split('.').pop() - const isAudio = ext in ['wav', 'mp3', 'ogg', 'aif', 'flac'] - const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` - const suffix = isAudio || options.noSizeUrlPart ? '' : getSizeUrlPart(options) - const subfolder = isAudio ? 'audio' : 'image' + if (!src.includes('discours.io') && src.includes('http')) { + return src + } + const filename = src.toLowerCase().split('/').pop() + const ext = filename.split('.').pop() + const isAudio = ext in ['wav', 'mp3', 'ogg', 'aif', 'flac'] + const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` + const suffix = isAudio || options.noSizeUrlPart ? '' : getSizeUrlPart(options) + const subfolder = isAudio ? 'audio' : 'image' - return `${base}${suffix}production/${subfolder}/${filename}` + return `${base}${suffix}production/${subfolder}/${filename}` } export const getOpenGraphImageUrl = ( From ddaed0557d3e862aecc18133abb1d0e7d1ddf635 Mon Sep 17 00:00:00 2001 From: kvakazyambra Date: Tue, 26 Mar 2024 16:57:24 +0300 Subject: [PATCH 02/36] Fixed topic body render (#429) Fixed topic body render --- src/components/Topic/Full.tsx | 2 +- src/components/Topic/TopicBadge/TopicBadge.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Topic/Full.tsx b/src/components/Topic/Full.tsx index 492a9113..5e22aed1 100644 --- a/src/components/Topic/Full.tsx +++ b/src/components/Topic/Full.tsx @@ -40,7 +40,7 @@ export const FullTopic = (props: Props) => { return (

#{props.topic?.title}

-

{props.topic?.body}

+

} > -
{props.topic.body}
+
From 78dd43a497cf51240f3717db3f781fdd0d74ba61 Mon Sep 17 00:00:00 2001 From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com> Date: Wed, 27 Mar 2024 03:54:15 +0300 Subject: [PATCH 03/36] Fix expo article length (#431) --- src/components/Views/Expo/Expo.tsx | 39 +++++++++++++----------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/components/Views/Expo/Expo.tsx b/src/components/Views/Expo/Expo.tsx index eddd12a4..7cc5ee6a 100644 --- a/src/components/Views/Expo/Expo.tsx +++ b/src/components/Views/Expo/Expo.tsx @@ -24,8 +24,8 @@ type Props = { layout: LayoutType } -export const PRERENDERED_ARTICLES_COUNT = 37 -const LOAD_MORE_PAGE_SIZE = 11 +export const PRERENDERED_ARTICLES_COUNT = 36 +const LOAD_MORE_PAGE_SIZE = 12 export const Expo = (props: Props) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.shouts)) @@ -34,11 +34,10 @@ export const Expo = (props: Props) => { const [randomTopArticles, setRandomTopArticles] = createSignal([]) const [randomTopMonthArticles, setRandomTopMonthArticles] = createSignal([]) + console.log('%c!!! randomTopMonthArticles():', 'color: #bada55', randomTopMonthArticles()) + const { t } = useLocalize() - // const { sortedArticles } = useArticlesStore({ - // shouts: isLoaded() ? props.shouts : [], - // }) const { sortedArticles } = useArticlesStore({ shouts: props.shouts || [], layout: props.layout, @@ -84,7 +83,7 @@ export const Expo = (props: Props) => { limit: 10, random_limit: 100, } - + console.log('%c!!! options:', 'color: #bada55', options) const result = await apiClient.getRandomTopShouts({ options }) setRandomTopArticles(result) } @@ -202,7 +201,7 @@ export const Expo = (props: Props) => {
- + {(shout) => (
{ 0} keyed={true}> - + {(shout) => (
{ 0} keyed={true}> - - {(page) => ( - - {(shout) => ( -
- -
- )} -
+ + {(shout) => ( +
+ +
)}
From 0b88357f7ce0f490ca889cb4a932e191a3cc46fc Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Fri, 29 Mar 2024 12:30:38 +0300 Subject: [PATCH 04/36] Fix expo --- src/components/Views/Expo/Expo.tsx | 10 ++++------ src/components/Views/Topic.tsx | 3 +-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/Views/Expo/Expo.tsx b/src/components/Views/Expo/Expo.tsx index 7cc5ee6a..b161660a 100644 --- a/src/components/Views/Expo/Expo.tsx +++ b/src/components/Views/Expo/Expo.tsx @@ -26,6 +26,7 @@ type Props = { export const PRERENDERED_ARTICLES_COUNT = 36 const LOAD_MORE_PAGE_SIZE = 12 +const PARTIAL_PAGE_SIZE = 8 export const Expo = (props: Props) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.shouts)) @@ -34,8 +35,6 @@ export const Expo = (props: Props) => { const [randomTopArticles, setRandomTopArticles] = createSignal([]) const [randomTopMonthArticles, setRandomTopMonthArticles] = createSignal([]) - console.log('%c!!! randomTopMonthArticles():', 'color: #bada55', randomTopMonthArticles()) - const { t } = useLocalize() const { sortedArticles } = useArticlesStore({ @@ -50,7 +49,7 @@ export const Expo = (props: Props) => { if (props.layout) { filters.layouts.push(props.layout) } else { - filters.layouts.push('article') + filters.layouts.push('audio', 'video', 'image', 'literature') } return filters @@ -83,7 +82,6 @@ export const Expo = (props: Props) => { limit: 10, random_limit: 100, } - console.log('%c!!! options:', 'color: #bada55', options) const result = await apiClient.getRandomTopShouts({ options }) setRandomTopArticles(result) } @@ -201,7 +199,7 @@ export const Expo = (props: Props) => {
- + {(shout) => (
{ 0} keyed={true}> - + {(shout) => (
{ /> - { 15}> - + From 75d929efdaa725ca4de37dd132617420df016c4d Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Fri, 29 Mar 2024 12:35:01 +0300 Subject: [PATCH 05/36] Fix expo --- src/components/Views/Expo/Expo.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/Views/Expo/Expo.tsx b/src/components/Views/Expo/Expo.tsx index b161660a..014af20f 100644 --- a/src/components/Views/Expo/Expo.tsx +++ b/src/components/Views/Expo/Expo.tsx @@ -26,7 +26,6 @@ type Props = { export const PRERENDERED_ARTICLES_COUNT = 36 const LOAD_MORE_PAGE_SIZE = 12 -const PARTIAL_PAGE_SIZE = 8 export const Expo = (props: Props) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.shouts)) @@ -199,7 +198,7 @@ export const Expo = (props: Props) => {
- + {(shout) => (
{ 0} keyed={true}> - + {(shout) => (
{ 0} keyed={true}> - + {(shout) => (
Date: Fri, 29 Mar 2024 12:47:56 +0300 Subject: [PATCH 06/36] Fix expo types --- src/context/following.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/context/following.tsx b/src/context/following.tsx index f3208ca9..4076941b 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -2,10 +2,16 @@ import { Accessor, JSX, createContext, createEffect, createSignal, useContext } import { createStore } from 'solid-js/store' import { apiClient } from '../graphql/client/core' -import { AuthorFollows, FollowingEntity } from '../graphql/schema/core.gen' +import { Author, Community, FollowingEntity, Topic } from '../graphql/schema/core.gen' import { useSession } from './session' +type AuthorFollows = { + topics: Topic[] + authors: Author[] + communities: Community[] +} + interface FollowingContextType { loading: Accessor subscriptions: AuthorFollows From ce0c2c0f0ac17809f0717f92385f7c50a4df8639 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Fri, 29 Mar 2024 12:58:32 +0300 Subject: [PATCH 07/36] Fix expo types --- src/context/following.tsx | 16 +++++----------- src/graphql/client/core.ts | 4 ++-- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/context/following.tsx b/src/context/following.tsx index 4076941b..1b0aa059 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -2,20 +2,14 @@ import { Accessor, JSX, createContext, createEffect, createSignal, useContext } import { createStore } from 'solid-js/store' import { apiClient } from '../graphql/client/core' -import { Author, Community, FollowingEntity, Topic } from '../graphql/schema/core.gen' +import { AuthorFollowsResult, FollowingEntity } from '../graphql/schema/core.gen' import { useSession } from './session' -type AuthorFollows = { - topics: Topic[] - authors: Author[] - communities: Community[] -} - interface FollowingContextType { loading: Accessor - subscriptions: AuthorFollows - setSubscriptions: (subscriptions: AuthorFollows) => void + subscriptions: AuthorFollowsResult + setSubscriptions: (subscriptions: AuthorFollowsResult) => void setFollowing: (what: FollowingEntity, slug: string, value: boolean) => void loadSubscriptions: () => void follow: (what: FollowingEntity, slug: string) => Promise @@ -29,7 +23,7 @@ export function useFollowing() { return useContext(FollowingContext) } -const EMPTY_SUBSCRIPTIONS: AuthorFollows = { +const EMPTY_SUBSCRIPTIONS: AuthorFollowsResult = { topics: [], authors: [], communities: [], @@ -37,7 +31,7 @@ const EMPTY_SUBSCRIPTIONS: AuthorFollows = { export const FollowingProvider = (props: { children: JSX.Element }) => { const [loading, setLoading] = createSignal(false) - const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) + const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) const { author, session } = useSession() const fetchData = async () => { diff --git a/src/graphql/client/core.ts b/src/graphql/client/core.ts index e7d8708e..e80f2e6d 100644 --- a/src/graphql/client/core.ts +++ b/src/graphql/client/core.ts @@ -1,6 +1,6 @@ import type { Author, - AuthorFollows, + AuthorFollowsResult, CommonResult, FollowingEntity, LoadShoutsOptions, @@ -134,7 +134,7 @@ export const apiClient = { slug?: string author_id?: number user?: string - }): Promise => { + }): Promise => { const response = await publicGraphQLClient.query(authorFollows, params).toPromise() return response.data.get_author_follows }, From 5e5693332ce9586229aa6443293d2489640aa114 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Fri, 29 Mar 2024 16:53:26 +0300 Subject: [PATCH 08/36] Load more fix --- src/components/Views/Expo/Expo.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Views/Expo/Expo.tsx b/src/components/Views/Expo/Expo.tsx index 014af20f..902f9dd9 100644 --- a/src/components/Views/Expo/Expo.tsx +++ b/src/components/Views/Expo/Expo.tsx @@ -37,7 +37,7 @@ export const Expo = (props: Props) => { const { t } = useLocalize() const { sortedArticles } = useArticlesStore({ - shouts: props.shouts || [], + shouts: isLoaded() ? props.shouts : [], layout: props.layout, }) @@ -228,7 +228,7 @@ export const Expo = (props: Props) => { 0} keyed={true}> - + {(shout) => (
Date: Fri, 29 Mar 2024 20:25:07 +0300 Subject: [PATCH 09/36] Fix Topic Top Articles --- src/components/Views/Expo/Expo.tsx | 35 +++++++++--------- src/components/Views/Topic.tsx | 58 +++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/components/Views/Expo/Expo.tsx b/src/components/Views/Expo/Expo.tsx index 902f9dd9..cf30bfe3 100644 --- a/src/components/Views/Expo/Expo.tsx +++ b/src/components/Views/Expo/Expo.tsx @@ -31,8 +31,8 @@ export const Expo = (props: Props) => { const [isLoaded, setIsLoaded] = createSignal(Boolean(props.shouts)) const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) - const [randomTopArticles, setRandomTopArticles] = createSignal([]) - const [randomTopMonthArticles, setRandomTopMonthArticles] = createSignal([]) + const [favoriteTopArticles, setFavoriteTopArticles] = createSignal([]) + const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal([]) const { t } = useLocalize() @@ -42,7 +42,7 @@ export const Expo = (props: Props) => { }) const getLoadShoutsFilters = (additionalFilters: LoadShoutsFilters = {}): LoadShoutsFilters => { - const filters = { featured: true, ...additionalFilters } + const filters = { ...additionalFilters } if (!filters.layouts) filters.layouts = [] if (props.layout) { @@ -77,12 +77,12 @@ export const Expo = (props: Props) => { const loadRandomTopArticles = async () => { const options: LoadShoutsOptions = { - filters: getLoadShoutsFilters(), + filters: { ...getLoadShoutsFilters(), featured: true }, limit: 10, random_limit: 100, } const result = await apiClient.getRandomTopShouts({ options }) - setRandomTopArticles(result) + setFavoriteTopArticles(result) } const loadRandomTopMonthArticles = async () => { @@ -90,19 +90,15 @@ export const Expo = (props: Props) => { const after = getUnixtime(new Date(now.setMonth(now.getMonth() - 1))) const options: LoadShoutsOptions = { - filters: getLoadShoutsFilters({ after }), + filters: { ...getLoadShoutsFilters({ after }), reacted: true }, limit: 10, random_limit: 10, } const result = await apiClient.getRandomTopShouts({ options }) - setRandomTopMonthArticles(result) + setReactedTopMonthArticles(result) } - const pages = createMemo(() => - splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE), - ) - onMount(() => { if (isLoaded()) { return @@ -126,8 +122,8 @@ export const Expo = (props: Props) => { () => props.layout, () => { resetSortedArticles() - setRandomTopArticles([]) - setRandomTopMonthArticles([]) + setFavoriteTopArticles([]) + setReactedTopMonthArticles([]) loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE) loadRandomTopArticles() loadRandomTopMonthArticles() @@ -140,8 +136,9 @@ export const Expo = (props: Props) => { }) const handleLoadMoreClick = () => { - loadMoreWithoutScrolling(LOAD_MORE_PAGE_SIZE) - } + loadMoreWithoutScrolling(LOAD_MORE_PAGE_SIZE); + }; + return (
@@ -210,8 +207,8 @@ export const Expo = (props: Props) => {
)} - 0} keyed={true}> - + 0} keyed={true}> + {(shout) => ( @@ -225,8 +222,8 @@ export const Expo = (props: Props) => {
)}
- 0} keyed={true}> - + 0} keyed={true}> + {(shout) => ( diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index 64fae425..e257db39 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -1,8 +1,8 @@ -import type { Shout, Topic } from '../../graphql/schema/core.gen' +import { LoadShoutsOptions, Shout, Topic } from "../../graphql/schema/core.gen"; import { Meta } from '@solidjs/meta' import { clsx } from 'clsx' -import { For, Show, createEffect, createMemo, createSignal, onMount } from 'solid-js' +import { For, Show, createEffect, createMemo, createSignal, onMount, on } from "solid-js"; import { useLocalize } from '../../context/localize' import { useRouter } from '../../stores/router' @@ -22,6 +22,8 @@ import { FullTopic } from '../Topic/Full' import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper' import styles from '../../styles/Topic.module.scss' +import { apiClient } from "../../graphql/client/core"; +import { getUnixtime } from "../../utils/getServerDate"; type TopicsPageSearchParams = { by: 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'commented' @@ -43,14 +45,57 @@ export const TopicView = (props: Props) => { const { sortedArticles } = useArticlesStore({ shouts: props.shouts }) const { topicEntities } = useTopicsStore({ topics: [props.topic] }) const { authorsByTopic } = useAuthorsStore() + const [favoriteTopArticles, setFavoriteTopArticles] = createSignal([]) + const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal([]) + + + console.log('%c!!! :', 'color: #bada55', sortedArticles()) const [topic, setTopic] = createSignal() + createEffect(() => { const topics = topicEntities() if (props.topicSlug && !topic() && topics) { setTopic(topics[props.topicSlug]) } }) + + const loadRandomTopArticles = async (topic: string) => { + const options: LoadShoutsOptions = { + filters: { featured: true, topic: topic}, + limit: 10, + random_limit: 100, + } + const result = await apiClient.getRandomTopShouts({ options }) + setFavoriteTopArticles(result) + } + + const loadRandomTopMonthArticles = async (topic: string) => { + const now = new Date() + const after = getUnixtime(new Date(now.setMonth(now.getMonth() - 1))) + + const options: LoadShoutsOptions = { + filters: { after: after, featured: true, topic: topic }, + limit: 10, + random_limit: 10, + } + + const result = await apiClient.getRandomTopShouts({ options }) + setReactedTopMonthArticles(result) + } + + + createEffect( + on( + () => topic(), + () => { + loadRandomTopArticles(topic()?.slug) + loadRandomTopMonthArticles(topic()?.slug) + }, + { defer: true }, + ), + ) + const title = createMemo( () => `#${capitalize( @@ -170,8 +215,9 @@ export const TopicView = (props: Props) => { beside={sortedArticles()[4]} wrapper={'author'} /> - - + 0} keyed={true}> + + { + 0} keyed={true}> + + 15}> - From d5aa083a2f1896b20eb4f6d9328cf82c323479aa Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Fri, 29 Mar 2024 20:25:17 +0300 Subject: [PATCH 10/36] Fix Topic Top Articles --- src/components/Views/Expo/Expo.tsx | 5 ++--- src/components/Views/Topic.tsx | 12 +++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/components/Views/Expo/Expo.tsx b/src/components/Views/Expo/Expo.tsx index cf30bfe3..82e43dfe 100644 --- a/src/components/Views/Expo/Expo.tsx +++ b/src/components/Views/Expo/Expo.tsx @@ -136,9 +136,8 @@ export const Expo = (props: Props) => { }) const handleLoadMoreClick = () => { - loadMoreWithoutScrolling(LOAD_MORE_PAGE_SIZE); - }; - + loadMoreWithoutScrolling(LOAD_MORE_PAGE_SIZE) + } return (
diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index e257db39..e3a512e1 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -1,8 +1,8 @@ -import { LoadShoutsOptions, Shout, Topic } from "../../graphql/schema/core.gen"; +import { LoadShoutsOptions, Shout, Topic } from '../../graphql/schema/core.gen' import { Meta } from '@solidjs/meta' import { clsx } from 'clsx' -import { For, Show, createEffect, createMemo, createSignal, onMount, on } from "solid-js"; +import { For, Show, createEffect, createMemo, createSignal, on, onMount } from 'solid-js' import { useLocalize } from '../../context/localize' import { useRouter } from '../../stores/router' @@ -21,9 +21,9 @@ import { Row3 } from '../Feed/Row3' import { FullTopic } from '../Topic/Full' import { ArticleCardSwiper } from '../_shared/SolidSwiper/ArticleCardSwiper' +import { apiClient } from '../../graphql/client/core' import styles from '../../styles/Topic.module.scss' -import { apiClient } from "../../graphql/client/core"; -import { getUnixtime } from "../../utils/getServerDate"; +import { getUnixtime } from '../../utils/getServerDate' type TopicsPageSearchParams = { by: 'comments' | '' | 'recent' | 'viewed' | 'rating' | 'commented' @@ -48,7 +48,6 @@ export const TopicView = (props: Props) => { const [favoriteTopArticles, setFavoriteTopArticles] = createSignal([]) const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal([]) - console.log('%c!!! :', 'color: #bada55', sortedArticles()) const [topic, setTopic] = createSignal() @@ -62,7 +61,7 @@ export const TopicView = (props: Props) => { const loadRandomTopArticles = async (topic: string) => { const options: LoadShoutsOptions = { - filters: { featured: true, topic: topic}, + filters: { featured: true, topic: topic }, limit: 10, random_limit: 100, } @@ -84,7 +83,6 @@ export const TopicView = (props: Props) => { setReactedTopMonthArticles(result) } - createEffect( on( () => topic(), From 9d5ddcfccc41db44e8ff3d92685100f45a9587a1 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Mon, 1 Apr 2024 07:16:53 +0300 Subject: [PATCH 11/36] Show saving status in ProfileSettings --- src/components/ProfileSettings/ProfileSettings.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/components/ProfileSettings/ProfileSettings.tsx b/src/components/ProfileSettings/ProfileSettings.tsx index 70389ccb..1891ddeb 100644 --- a/src/components/ProfileSettings/ProfileSettings.tsx +++ b/src/components/ProfileSettings/ProfileSettings.tsx @@ -33,6 +33,7 @@ export const ProfileSettings = () => { const { t } = useLocalize() const [prevForm, setPrevForm] = createStore({}) const [isFormInitialized, setIsFormInitialized] = createSignal(false) + const [isSaving, setIsSaving] = createSignal(false) const [social, setSocial] = createSignal([]) const [addLinkForm, setAddLinkForm] = createSignal(false) const [incorrectUrl, setIncorrectUrl] = createSignal(false) @@ -70,16 +71,20 @@ export const ProfileSettings = () => { const handleSubmit = async (event: Event) => { event.preventDefault() + setIsSaving(true) if (nameInputRef.current.value.length === 0) { setNameError(t('Required')) nameInputRef.current.focus() + setIsSaving(false) return } if (slugInputRef.current.value.length === 0) { setSlugError(t('Required')) slugInputRef.current.focus() + setIsSaving(false) return } + try { await submit(form) setPrevForm(clone(form)) @@ -91,6 +96,8 @@ export const ProfileSettings = () => { return } showSnackbar({ type: 'error', body: t('Error') }) + } finally { + setIsSaving(false) } await loadAuthor() // renews author's profile @@ -359,7 +366,12 @@ export const ProfileSettings = () => { } onClick={handleCancel} /> -
From e93cb76a78cc6b43167223227aa9861f4463bd54 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Tue, 2 Apr 2024 06:12:29 +0300 Subject: [PATCH 12/36] Disallow in robots txt --- public/robots.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/robots.txt b/public/robots.txt index c2a49f4f..1f53798b 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,2 +1,2 @@ User-agent: * -Allow: / +Disallow: / From d55be2505d3a958ccae33b5651ab022a1764f575 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Tue, 2 Apr 2024 14:27:56 +0300 Subject: [PATCH 13/36] load Random Topics on Mount --- src/components/Views/Topic.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index e3a512e1..520f8ba8 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -59,7 +59,7 @@ export const TopicView = (props: Props) => { } }) - const loadRandomTopArticles = async (topic: string) => { + const loadFavoriteTopArticles = async (topic: string) => { const options: LoadShoutsOptions = { filters: { featured: true, topic: topic }, limit: 10, @@ -69,7 +69,7 @@ export const TopicView = (props: Props) => { setFavoriteTopArticles(result) } - const loadRandomTopMonthArticles = async (topic: string) => { + const loadReactedTopMonthArticles = async (topic: string) => { const now = new Date() const after = getUnixtime(new Date(now.setMonth(now.getMonth() - 1))) @@ -80,16 +80,21 @@ export const TopicView = (props: Props) => { } const result = await apiClient.getRandomTopShouts({ options }) + setReactedTopMonthArticles(result) } + + const loadRandom = () => { + console.log("!!! loadRandom:"); + loadFavoriteTopArticles(topic()?.slug) + loadReactedTopMonthArticles(topic()?.slug) + } + createEffect( on( () => topic(), - () => { - loadRandomTopArticles(topic()?.slug) - loadRandomTopMonthArticles(topic()?.slug) - }, + () => loadRandom(), { defer: true }, ), ) @@ -118,6 +123,7 @@ export const TopicView = (props: Props) => { } onMount(() => { + loadRandom() if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) { loadMore() } From b9591d7364bc33ab87e894a81081e9ae3010e628 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Tue, 2 Apr 2024 14:28:43 +0300 Subject: [PATCH 14/36] Cleanup code --- src/components/Views/Topic.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/Views/Topic.tsx b/src/components/Views/Topic.tsx index 520f8ba8..97a107dd 100644 --- a/src/components/Views/Topic.tsx +++ b/src/components/Views/Topic.tsx @@ -48,8 +48,6 @@ export const TopicView = (props: Props) => { const [favoriteTopArticles, setFavoriteTopArticles] = createSignal([]) const [reactedTopMonthArticles, setReactedTopMonthArticles] = createSignal([]) - console.log('%c!!! :', 'color: #bada55', sortedArticles()) - const [topic, setTopic] = createSignal() createEffect(() => { @@ -84,9 +82,7 @@ export const TopicView = (props: Props) => { setReactedTopMonthArticles(result) } - const loadRandom = () => { - console.log("!!! loadRandom:"); loadFavoriteTopArticles(topic()?.slug) loadReactedTopMonthArticles(topic()?.slug) } From b752357224678e6422f22e59045d72d614a8da26 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Thu, 4 Apr 2024 09:01:26 +0300 Subject: [PATCH 15/36] Fix profile settings Is Floating PanelVisible --- .../ProfileSettings/ProfileSettings.tsx | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/components/ProfileSettings/ProfileSettings.tsx b/src/components/ProfileSettings/ProfileSettings.tsx index 1891ddeb..b03b6aa8 100644 --- a/src/components/ProfileSettings/ProfileSettings.tsx +++ b/src/components/ProfileSettings/ProfileSettings.tsx @@ -1,7 +1,18 @@ import { createFileUploader } from '@solid-primitives/upload' import { clsx } from 'clsx' import deepEqual from 'fast-deep-equal' -import { For, Match, Show, Switch, createEffect, createSignal, lazy, onCleanup, onMount } from 'solid-js' +import { + For, + Match, + Show, + Switch, + createEffect, + createSignal, + lazy, + onCleanup, + onMount, + on +} from "solid-js"; import { createStore } from 'solid-js/store' import { useConfirm } from '../../context/confirm' @@ -156,12 +167,15 @@ export const ProfileSettings = () => { onCleanup(() => window.removeEventListener('beforeunload', handleBeforeUnload)) }) - createEffect(() => { - if (!deepEqual(form, prevForm)) { - setIsFloatingPanelVisible(true) - } - }) - + createEffect( + on( + () => deepEqual(form, prevForm), + () => { + setIsFloatingPanelVisible(!deepEqual(form, prevForm)) + }, + { defer: true } + ), + ) const handleDeleteSocialLink = (link) => { updateFormField('links', link, true) } From c3495ed0b32ac12b1e51473b2857c24e5584bb22 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Thu, 4 Apr 2024 09:02:34 +0300 Subject: [PATCH 16/36] Fil lint --- src/components/ProfileSettings/ProfileSettings.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ProfileSettings/ProfileSettings.tsx b/src/components/ProfileSettings/ProfileSettings.tsx index b03b6aa8..90a23b33 100644 --- a/src/components/ProfileSettings/ProfileSettings.tsx +++ b/src/components/ProfileSettings/ProfileSettings.tsx @@ -9,10 +9,10 @@ import { createEffect, createSignal, lazy, + on, onCleanup, onMount, - on -} from "solid-js"; +} from 'solid-js' import { createStore } from 'solid-js/store' import { useConfirm } from '../../context/confirm' @@ -173,7 +173,7 @@ export const ProfileSettings = () => { () => { setIsFloatingPanelVisible(!deepEqual(form, prevForm)) }, - { defer: true } + { defer: true }, ), ) const handleDeleteSocialLink = (link) => { From 6851c3af6ad9c8a057bc87c2949f2928a4f6bf76 Mon Sep 17 00:00:00 2001 From: kvakazyambra Date: Mon, 8 Apr 2024 14:26:20 +0300 Subject: [PATCH 17/36] Feature/header (#408) New header --- public/locales/en/translation.json | 1 + public/locales/ru/translation.json | 1 + src/components/Nav/Header/Header.module.scss | 202 ++++++++++++++----- src/components/Nav/HeaderAuth.tsx | 121 ++++++++--- src/components/Nav/Snackbar.module.scss | 1 - src/components/_shared/Icon/Icon.module.scss | 21 +- src/styles/app.scss | 4 + 7 files changed, 262 insertions(+), 89 deletions(-) diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 7c097558..32f06587 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -83,6 +83,7 @@ "Coming soon": "Coming soon", "Comment successfully deleted": "Comment successfully deleted", "Commentator": "Commentator", + "Commenting": "Commenting", "Comments": "Comments", "CommentsWithCount": "{count, plural, =0 {{count} comments} one {{count} comment} few {{count} comments} other {{count} comments}}", "Communities": "Communities", diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 6dfe2bbd..fc28e27e 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -87,6 +87,7 @@ "Comment successfully deleted": "Комментарий успешно удален", "Comment": "Комментировать", "Commentator": "Комментатор", + "Commenting": "Комментирование", "Comments": "Комментарии", "CommentsWithCount": "{count, plural, =0 {{count} комментариев} one {{count} комментарий} few {{count} комментария} other {{count} комментариев}}", "Communities": "Сообщества", diff --git a/src/components/Nav/Header/Header.module.scss b/src/components/Nav/Header/Header.module.scss index 018adc78..660a2245 100644 --- a/src/components/Nav/Header/Header.module.scss +++ b/src/components/Nav/Header/Header.module.scss @@ -114,6 +114,11 @@ position: absolute; right: 0; } + + .control { + align-items: center; + display: flex; + } } .mainNavigationWrapper { @@ -192,15 +197,8 @@ padding: divide($container-padding-x, 2) !important; } - @include media-breakpoint-up(md) { - span, - button { - padding: 0 0.4rem; - } - } - :global(.view-switcher) { - margin: 0 -0.5rem; + margin: 0; overflow: hidden; padding: 0; } @@ -299,9 +297,6 @@ .burgerContainer { box-sizing: content-box; display: inline-flex; - padding-left: 0; - - // float: right; @include media-breakpoint-up(sm) { padding-left: divide($container-padding-x, 2); @@ -430,12 +425,15 @@ width: 100%; @include media-breakpoint-up(xl) { - right: 2rem; + right: 9rem; } .control { - cursor: pointer; border: 0; + cursor: pointer; + height: 3.2rem; + margin: 0 0.6rem; + width: 3.2rem; &:hover { background: none; @@ -451,11 +449,7 @@ } .control + .control { - margin-left: 1.2rem; - - @include media-breakpoint-up(sm) { - margin-left: 2rem; - } + margin: 0 0.6rem; } img { @@ -497,10 +491,15 @@ } } + .settingsControlContainer { + margin-left: 1rem !important; + margin-right: 2rem !important; + } + .settingsControl { border-radius: 100%; - padding: 0.8rem !important; min-width: 4rem !important; + padding: 0.8rem !important; &:hover { background: var(--background-color-invert); @@ -516,12 +515,18 @@ align-items: center; border-radius: 100%; display: flex; - height: 2.4em; + height: 2.8rem; justify-content: center; - margin-left: 0.3rem; + margin: 0 0.4rem; position: relative; transition: margin-left 0.3s; - width: 2.4em; + width: 2.8rem; + + @include media-breakpoint-up(md) { + height: 3.2rem; + margin: 0 0.7rem; + width: 3.2rem; + } @include media-breakpoint-down(sm) { margin-left: 0.4rem !important; @@ -543,12 +548,13 @@ a:link { border: none; cursor: pointer; - height: auto; + height: 100%; margin: 0; padding: 0; + width: 100%; &:hover { - background: none !important; + background: none; .icon { display: none; @@ -571,6 +577,20 @@ } } +.userControlItemSearch { + margin: 0 1rem 0 2.2rem; +} + +.userControlItemUserpic { + height: 3.2rem; + width: 3.2rem; + + @include media-breakpoint-up(md) { + height: 4rem; + width: 4rem; + } +} + .userControlItemInbox, .userControlItemSearch { @include media-breakpoint-down(sm) { @@ -579,7 +599,16 @@ } .userControlItemVerbose { - margin-left: 0.9em !important; + align-items: stretch; + display: flex; + height: 3.2rem; + margin-left: 1rem !important; + width: 3.2rem; + + @include media-breakpoint-up(md) { + height: 4rem; + width: 4rem; + } &:first-child { margin-left: 0 !important; @@ -590,6 +619,7 @@ @include media-breakpoint-up(xl) { background: none; + margin-left: 0.8rem !important; } .icon { @@ -611,10 +641,14 @@ } @include media-breakpoint-up(xl) { - margin-left: 0.5em !important; - margin-right: 0.5em; + margin-left: 3rem !important; + margin-right: 0; width: auto; + &:last-child { + margin-right: 0; + } + .icon { display: none !important; } @@ -629,6 +663,37 @@ } } + a:link, + a:visited, + button { + align-items: center; + display: flex; + justify-content: center; + + @include media-breakpoint-up(xl) { + border-radius: 2rem; + box-shadow: inset 0 0 0 2px #000; + padding: 0 2rem; + } + + &:hover { + background-color: var(--link-hover-background); + + &, + .textLabel { + color: #fff !important; + } + + .icon { + display: none; + } + + .iconHover { + display: block; + } + } + } + button { margin: 0 !important; } @@ -636,27 +701,6 @@ a::before { display: none; } - - a:hover, - button:hover { - .icon { - display: none; - } - - .iconHover { - display: block; - } - - .textLabel { - color: var(--link-hover-color); - } - } - - a:hover { - .textLabel { - background-color: var(--link-hover-background); - } - } } .subnavigation { @@ -746,3 +790,65 @@ position: relative; top: 0.15em; } + +.editorPopup { + border: 1px solid rgb(0 0 0 / 15%) !important; + border-radius: 1.6rem; + line-height: 1.3; + min-width: 28rem; + padding: 1.6rem !important; +} + +.editorModePopupOpener { + display: inline-block; + margin-right: 2rem; + position: relative; + text-align: right; + width: 9em; +} + +.editorModePopupOpenerIcon { + height: 2rem; + left: 100%; + margin-left: 0.2em; + top: 0; + transform: rotate(90deg); + position: absolute; + width: 2rem; +} + +.editorModesList { + li { + cursor: pointer; + margin-bottom: 1.6rem; + padding-left: 3rem !important; + position: relative; + + &:hover { + opacity: 0.6; + } + } + + .editorModesSelected { + cursor: default; + opacity: 0.6; + } +} + +.editorModeTitle { + color: #000; + margin-bottom: 0.5rem; +} + +.editorModeDescription { + color: #696969; + font-size: 1.2rem; +} + +.editorModeIcon { + height: 2.4rem; + left: 0; + position: absolute; + top: -0.2em; + width: 2.4rem; +} diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index 31a0acc6..2b6b1ea3 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -17,6 +17,8 @@ import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient' import { ProfilePopup } from './ProfilePopup' import { useSnackbar } from '../../context/snackbar' +import { Popup } from '../_shared/Popup' +import { VotersList } from '../_shared/VotersList' import styles from './Header/Header.module.scss' type Props = { @@ -51,7 +53,7 @@ export const HeaderAuth = (props: Props) => { const isEditorPage = createMemo(() => page().route === 'edit' || page().route === 'editSettings') const isNotificationsVisible = createMemo(() => isAuthenticated() && !isEditorPage()) const isSaveButtonVisible = createMemo(() => isAuthenticated() && isEditorPage()) - const isCreatePostButtonVisible = createMemo(() => isAuthenticated() && !isEditorPage()) + const isCreatePostButtonVisible = createMemo(() => !isEditorPage()) const isAuthenticatedControlsVisible = createMemo( () => isAuthenticated() && session()?.user?.email_verified, ) @@ -65,6 +67,7 @@ export const HeaderAuth = (props: Props) => { } const [width, setWidth] = createSignal(0) + const [editorMode, setEditorMode] = createSignal(t('Editing')) onMount(() => { const handleResize = () => setWidth(window.innerWidth) @@ -106,7 +109,7 @@ export const HeaderAuth = (props: Props) => {
- +
{t('Create post')} @@ -117,7 +120,7 @@ export const HeaderAuth = (props: Props) => { - diff --git a/src/components/Nav/Snackbar.module.scss b/src/components/Nav/Snackbar.module.scss index a0fb8e64..9af5719b 100644 --- a/src/components/Nav/Snackbar.module.scss +++ b/src/components/Nav/Snackbar.module.scss @@ -1,5 +1,4 @@ .snackbar { - min-height: 2px; background-color: var(--default-color); color: #fff; font-size: 2rem; diff --git a/src/components/_shared/Icon/Icon.module.scss b/src/components/_shared/Icon/Icon.module.scss index 6618efa9..4cafd050 100644 --- a/src/components/_shared/Icon/Icon.module.scss +++ b/src/components/_shared/Icon/Icon.module.scss @@ -10,18 +10,23 @@ } .notificationsCounter { - background-color: #d00820; - border: 2px solid #fff; - border-radius: 2em; + align-items: center; + background-color: #E84500; + border-radius: 0.8rem; color: #fff; - font-size: 1rem; + display: flex; + font-size: 1.2rem; font-weight: 700; - height: 1.6em; - left: 1.1em; - line-height: 1.25em; + height: 2.2rem; + justify-content: center; + left: 1.6rem; + min-width: 2.2rem; padding: 0 0.25em; position: absolute; text-align: center; top: -0.5rem; - min-width: 1.5em; + + @include media-breakpoint-up(md) { + left: 1.8rem; + } } diff --git a/src/styles/app.scss b/src/styles/app.scss index db3a68bc..7afcb070 100644 --- a/src/styles/app.scss +++ b/src/styles/app.scss @@ -622,6 +622,10 @@ figure { margin-bottom: 0.6em; white-space: nowrap; + @include media-breakpoint-up(md) { + margin-right: 2.4rem; + } + .link { border-bottom: none; } From 58c4d6eae7748cadcc1ab14747c5bf49ed349513 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 15:49:40 +0300 Subject: [PATCH 18/36] app-data-author --- src/components/Views/Author/Author.tsx | 26 +++++++++++----- .../ProfileSubscriptions.tsx | 30 ++++++++----------- src/context/following.tsx | 15 ++++++++-- src/context/session.tsx | 14 +++++++-- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index a21cebcc..efd1bb73 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -38,26 +38,36 @@ const LOAD_MORE_PAGE_SIZE = 9 export const AuthorView = (props: Props) => { const { t } = useLocalize() - const { loadSubscriptions } = useFollowing() + const { subscriptions, followers } = 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 [followers, setFollowers] = createSignal([]) + const [author, setAuthor] = createSignal() const [following, setFollowing] = createSignal>([]) const [showExpandBioControl, setShowExpandBioControl] = createSignal(false) const [commented, setCommented] = createSignal() const modal = MODALS[searchParams().m] // current author - const [author, setAuthor] = createSignal() createEffect(() => { - try { - const a = authorEntities()[props.authorSlug] - setAuthor(a) - } catch (error) { - console.debug(error) + if(props.authorSlug) { + if (session()?.user?.app_data?.profile?.slug === props.authorSlug) { + console.info('my own profile') + const {profile, authors, topics} = session().user.app_data + setAuthor(profile) + setFollowing([...authors, ...topics]) + } + } else { + try { + const a = authorEntities()[props.authorSlug] + setAuthor(a) + console.debug('[Author] expecting following data fetched') + } catch (error) { + console.debug(error) + } } }) diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index 6e1b4d8d..82fe575a 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -1,6 +1,7 @@ import { clsx } from 'clsx' import { For, Show, createEffect, 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' @@ -20,23 +21,20 @@ import stylesSettings from '../../../styles/FeedSettings.module.scss' export const ProfileSubscriptions = () => { const { t, lang } = useLocalize() - const { author } = useSession() - const [following, setFollowing] = createSignal>([]) - const [filtered, setFiltered] = createSignal>([]) - const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') + const { author, session } = useSession() + const { subscriptions } = useFollowing() + const [following, setFollowing] = (createSignal < Array < Author) | (Topic >> []) + const [filtered, setFiltered] = (createSignal < Array < Author) | (Topic >> []) + const [subscriptionFilter, setSubscriptionFilter] = createSignal < SubscriptionFilter > 'all' const [searchQuery, setSearchQuery] = createSignal('') - const fetchSubscriptions = async () => { - try { - const slug = author()?.slug - const authorFollows = await apiClient.getAuthorFollows({ slug }) - setFollowing([...authorFollows['authors']]) - setFiltered([...authorFollows['authors'], ...authorFollows['topics']]) - } catch (error) { - console.error('[fetchSubscriptions] :', error) - throw error + createEffect(() => { + if (subscriptions()) { + const { authors, topics } = subscriptions() + setFollowing([...authors, ...topics]) + setFiltered([...authors, ...topics]) } - } + }) createEffect(() => { if (following()) { @@ -53,10 +51,6 @@ export const ProfileSubscriptions = () => { } }) - onMount(async () => { - await fetchSubscriptions() - }) - return (
diff --git a/src/context/following.tsx b/src/context/following.tsx index f3208ca9..6ee4621e 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -2,12 +2,13 @@ import { Accessor, JSX, createContext, createEffect, createSignal, useContext } import { createStore } from 'solid-js/store' import { apiClient } from '../graphql/client/core' -import { AuthorFollows, FollowingEntity } from '../graphql/schema/core.gen' +import { AuthorFollows, FollowingEntity, Author } from '../graphql/schema/core.gen' import { useSession } from './session' interface FollowingContextType { loading: Accessor + followers: Accessor> subscriptions: AuthorFollows setSubscriptions: (subscriptions: AuthorFollows) => void setFollowing: (what: FollowingEntity, slug: string, value: boolean) => void @@ -31,6 +32,7 @@ const EMPTY_SUBSCRIPTIONS: AuthorFollows = { export const FollowingProvider = (props: { children: JSX.Element }) => { const [loading, setLoading] = createSignal(false) + const [followers, setFollowers] = createSignal>([]) const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) const { author, session } = useSession() @@ -77,8 +79,14 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { createEffect(() => { if (author()) { - console.debug('[context.following] author update detect') - fetchData() + try { + const { authors, followers, topics } = session().user.app_data + setSubscriptions({ authors, topics }) + setFollowers(followers) + if(!authors) fetchData() + } catch(e) { + console.error(e) + } } }) @@ -116,6 +124,7 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { setSubscriptions, isOwnerSubscribed, setFollowing, + followers, loadSubscriptions: fetchData, follow, unfollow, diff --git a/src/context/session.tsx b/src/context/session.tsx index 73659a6c..aba1ace5 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -199,6 +199,7 @@ export const SessionProvider = (props: { } onCleanup(() => clearTimeout(minuteLater)) + const authorData = async () => { const u = session()?.user return u ? (await apiClient.getAuthorId({ user: u.id.trim() })) || null : null @@ -217,7 +218,15 @@ export const SessionProvider = (props: { apiClient.connect(token) inboxClient.connect(token) } - if (!author()) loadAuthor() + + try { + const { profile } = session().user.app_data + setAuthor(profile) + addAuthors([profile]) + if(!profile) loadAuthor() + } catch(e) { + console.error(e) + } setIsSessionLoaded(true) } @@ -262,8 +271,7 @@ export const SessionProvider = (props: { () => props.onStateChangeCallback, () => { props.onStateChangeCallback(session()) - }, - { defer: true }, + } ), ) From 6d12b01d561b80a02a26c8f942152d5098d8e20e Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 15:54:01 +0300 Subject: [PATCH 19/36] author-type-fix --- src/components/Views/Author/Author.tsx | 4 ++-- .../ProfileSubscriptions.tsx | 6 +++--- src/context/following.tsx | 6 +++--- src/context/session.tsx | 6 +++--- src/utils/getImageUrl.ts | 20 +++++++++---------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index efd1bb73..e2de6c1f 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -53,10 +53,10 @@ export const AuthorView = (props: Props) => { // current author createEffect(() => { - if(props.authorSlug) { + if (props.authorSlug) { if (session()?.user?.app_data?.profile?.slug === props.authorSlug) { console.info('my own profile') - const {profile, authors, topics} = session().user.app_data + const { profile, authors, topics } = session().user.app_data setAuthor(profile) setFollowing([...authors, ...topics]) } diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index 82fe575a..cab28884 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -5,7 +5,7 @@ import { useFollowing } from '../../../context/following' import { useLocalize } from '../../../context/localize' import { useSession } from '../../../context/session' import { apiClient } from '../../../graphql/client/core' -import { Author, Topic } from '../../../graphql/schema/core.gen' +import { Author as AuthorType, Topic } from '../../../graphql/schema/core.gen' import { SubscriptionFilter } from '../../../pages/types' import { dummyFilter } from '../../../utils/dummyFilter' // TODO: refactor styles @@ -23,8 +23,8 @@ export const ProfileSubscriptions = () => { const { t, lang } = useLocalize() const { author, session } = useSession() const { subscriptions } = useFollowing() - const [following, setFollowing] = (createSignal < Array < Author) | (Topic >> []) - const [filtered, setFiltered] = (createSignal < Array < Author) | (Topic >> []) + const [following, setFollowing] = (createSignal < Array < AuthorType) | (Topic >> []) + const [filtered, setFiltered] = (createSignal < Array < AuthorType) | (Topic >> []) const [subscriptionFilter, setSubscriptionFilter] = createSignal < SubscriptionFilter > 'all' const [searchQuery, setSearchQuery] = createSignal('') diff --git a/src/context/following.tsx b/src/context/following.tsx index 6ee4621e..3371a010 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -2,7 +2,7 @@ import { Accessor, JSX, createContext, createEffect, createSignal, useContext } import { createStore } from 'solid-js/store' import { apiClient } from '../graphql/client/core' -import { AuthorFollows, FollowingEntity, Author } from '../graphql/schema/core.gen' +import { Author, AuthorFollows, FollowingEntity } from '../graphql/schema/core.gen' import { useSession } from './session' @@ -83,8 +83,8 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { const { authors, followers, topics } = session().user.app_data setSubscriptions({ authors, topics }) setFollowers(followers) - if(!authors) fetchData() - } catch(e) { + if (!authors) fetchData() + } catch (e) { console.error(e) } } diff --git a/src/context/session.tsx b/src/context/session.tsx index aba1ace5..67bd5a93 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -223,8 +223,8 @@ export const SessionProvider = (props: { const { profile } = session().user.app_data setAuthor(profile) addAuthors([profile]) - if(!profile) loadAuthor() - } catch(e) { + if (!profile) loadAuthor() + } catch (e) { console.error(e) } @@ -271,7 +271,7 @@ export const SessionProvider = (props: { () => props.onStateChangeCallback, () => { props.onStateChangeCallback(session()) - } + }, ), ) diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index 7b8b56dc..bc3c9073 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -15,17 +15,17 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { - if (!src.includes('discours.io') && src.includes('http')) { - return src - } - const filename = src.toLowerCase().split('/').pop() - const ext = filename.split('.').pop() - const isAudio = ext in ['wav', 'mp3', 'ogg', 'aif', 'flac'] - const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` - const suffix = isAudio || options.noSizeUrlPart ? '' : getSizeUrlPart(options) - const subfolder = isAudio ? 'audio' : 'image' + if (!src.includes('discours.io') && src.includes('http')) { + return src + } + const filename = src.toLowerCase().split('/').pop() + const ext = filename.split('.').pop() + const isAudio = ext in ['wav', 'mp3', 'ogg', 'aif', 'flac'] + const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` + const suffix = isAudio || options.noSizeUrlPart ? '' : getSizeUrlPart(options) + const subfolder = isAudio ? 'audio' : 'image' - return `${base}${suffix}production/${subfolder}/${filename}` + return `${base}${suffix}production/${subfolder}/${filename}` } export const getOpenGraphImageUrl = ( From 79961b7f47785873bedb0882979d85e28471c7df Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 16:04:10 +0300 Subject: [PATCH 20/36] fdata-fix --- .../ProfileSubscriptions.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index cab28884..f43445f7 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -31,21 +31,21 @@ export const ProfileSubscriptions = () => { createEffect(() => { if (subscriptions()) { const { authors, topics } = subscriptions() - setFollowing([...authors, ...topics]) - setFiltered([...authors, ...topics]) + const fdata = [...authors, ...topics] + if (fdata) { + setFollowing(fdata) + if (subscriptionFilter() === 'authors') { + setFiltered(fdata.filter((s) => 'name' in s)) + } else if (subscriptionFilter() === 'topics') { + setFiltered(fdata.filter((s) => 'title' in s)) + } else { + setFiltered(fdata) + } + } } }) createEffect(() => { - if (following()) { - if (subscriptionFilter() === 'authors') { - setFiltered(following().filter((s) => 'name' in s)) - } else if (subscriptionFilter() === 'topics') { - setFiltered(following().filter((s) => 'title' in s)) - } else { - setFiltered(following()) - } - } if (searchQuery()) { setFiltered(dummyFilter(following(), searchQuery(), lang())) } From aeb42de90879a0ec6e669080bcff461a63fc85b6 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 16:14:19 +0300 Subject: [PATCH 21/36] use-following-data --- .../ProfileSubscriptions.tsx | 22 +++++++++---------- src/context/following.tsx | 4 ++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index f43445f7..083e7978 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -29,18 +29,16 @@ export const ProfileSubscriptions = () => { const [searchQuery, setSearchQuery] = createSignal('') createEffect(() => { - if (subscriptions()) { - const { authors, topics } = subscriptions() - const fdata = [...authors, ...topics] - if (fdata) { - setFollowing(fdata) - if (subscriptionFilter() === 'authors') { - setFiltered(fdata.filter((s) => 'name' in s)) - } else if (subscriptionFilter() === 'topics') { - setFiltered(fdata.filter((s) => 'title' in s)) - } else { - setFiltered(fdata) - } + const { authors, topics } = subscriptions + if (authors || topics) { + const fdata = [...(authors || []), ...(topics || [])] + setFollowing(fdata) + if (subscriptionFilter() === 'authors') { + setFiltered(fdata.filter((s) => 'name' in s)) + } else if (subscriptionFilter() === 'topics') { + setFiltered(fdata.filter((s) => 'title' in s)) + } else { + setFiltered(fdata) } } }) diff --git a/src/context/following.tsx b/src/context/following.tsx index 6200c681..ad93eaaf 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -10,7 +10,7 @@ interface FollowingContextType { loading: Accessor followers: Accessor> subscriptions: AuthorFollowsResult - setSubscriptions: (subscriptions: AuthorFollows) => void + setSubscriptions: (subscriptions: AuthorFollowsResult) => void setFollowing: (what: FollowingEntity, slug: string, value: boolean) => void loadSubscriptions: () => void follow: (what: FollowingEntity, slug: string) => Promise @@ -33,7 +33,7 @@ const EMPTY_SUBSCRIPTIONS: AuthorFollowsResult = { export const FollowingProvider = (props: { children: JSX.Element }) => { const [loading, setLoading] = createSignal(false) const [followers, setFollowers] = createSignal>([]) - const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) + const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) const { author, session } = useSession() const fetchData = async () => { From cf0214563d94f0bc80ef0fb17eb8791463d88e74 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 17:48:58 +0300 Subject: [PATCH 22/36] use-following-data-2 --- package.json | 2 +- .../Author/AuthorCard/AuthorCard.tsx | 281 ++++++++------ src/components/Views/Author/Author.tsx | 354 ++++++++++++------ .../ProfileSubscriptions.tsx | 141 ++++--- 4 files changed, 493 insertions(+), 285 deletions(-) diff --git a/package.json b/package.json index 5e79d11f..1da95480 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "hygen": "HYGEN_TMPLS=gen hygen", "postinstall": "npm run codegen && npx patch-package", "check:code": "npx @biomejs/biome check src --log-kind=compact --verbose", - "check:code:fix": "npx @biomejs/biome check src --log-kind=compact --verbose --apply-unsafe", + "check:code:fix": "npx @biomejs/biome check src --log-kind=compact", "lint": "npm run lint:code && stylelint **/*.{scss,css}", "lint:code": "npx @biomejs/biome lint src --log-kind=compact --verbose", "lint:code:fix": "npx @biomejs/biome lint src --apply-unsafe --log-kind=compact --verbose", diff --git a/src/components/Author/AuthorCard/AuthorCard.tsx b/src/components/Author/AuthorCard/AuthorCard.tsx index 75f23639..b6054a58 100644 --- a/src/components/Author/AuthorCard/AuthorCard.tsx +++ b/src/components/Author/AuthorCard/AuthorCard.tsx @@ -1,119 +1,133 @@ -import type { Author, Community } from '../../../graphql/schema/core.gen' +import type { Author, Community } from "../../../graphql/schema/core.gen"; -import { openPage, redirectPage } from '@nanostores/router' -import { clsx } from 'clsx' -import { For, Show, createEffect, createMemo, createSignal, onMount } from 'solid-js' +import { openPage, redirectPage } from "@nanostores/router"; +import { clsx } from "clsx"; +import { + For, + Show, + createEffect, + createMemo, + createSignal, + onMount, +} from "solid-js"; -import { useFollowing } from '../../../context/following' -import { useLocalize } from '../../../context/localize' -import { useSession } from '../../../context/session' -import { FollowingEntity, Topic } from '../../../graphql/schema/core.gen' -import { SubscriptionFilter } from '../../../pages/types' -import { router, useRouter } from '../../../stores/router' -import { isAuthor } from '../../../utils/isAuthor' -import { translit } from '../../../utils/ru2en' -import { isCyrillic } from '../../../utils/translate' -import { SharePopup, getShareUrl } from '../../Article/SharePopup' -import { Modal } from '../../Nav/Modal' -import { TopicBadge } from '../../Topic/TopicBadge' -import { Button } from '../../_shared/Button' -import { ShowOnlyOnClient } from '../../_shared/ShowOnlyOnClient' -import { AuthorBadge } from '../AuthorBadge' -import { Userpic } from '../Userpic' +import { useFollowing } from "../../../context/following"; +import { useLocalize } from "../../../context/localize"; +import { useSession } from "../../../context/session"; +import { FollowingEntity, Topic } from "../../../graphql/schema/core.gen"; +import { SubscriptionFilter } from "../../../pages/types"; +import { router, useRouter } from "../../../stores/router"; +import { isAuthor } from "../../../utils/isAuthor"; +import { translit } from "../../../utils/ru2en"; +import { isCyrillic } from "../../../utils/translate"; +import { SharePopup, getShareUrl } from "../../Article/SharePopup"; +import { Modal } from "../../Nav/Modal"; +import { TopicBadge } from "../../Topic/TopicBadge"; +import { Button } from "../../_shared/Button"; +import { ShowOnlyOnClient } from "../../_shared/ShowOnlyOnClient"; +import { AuthorBadge } from "../AuthorBadge"; +import { Userpic } from "../Userpic"; -import stylesButton from '../../_shared/Button/Button.module.scss' -import styles from './AuthorCard.module.scss' +import stylesButton from "../../_shared/Button/Button.module.scss"; +import styles from "./AuthorCard.module.scss"; type Props = { - author: Author - followers?: Author[] - following?: Array -} + author: Author; + followers?: Author[]; + following?: Array; +}; export const AuthorCard = (props: Props) => { - const { t, lang } = useLocalize() - const { author, isSessionLoaded, requireAuthentication } = useSession() - const [authorSubs, setAuthorSubs] = createSignal>([]) - const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') - const [isFollowed, setIsFollowed] = createSignal() - const isProfileOwner = createMemo(() => author()?.slug === props.author.slug) - const { setFollowing, isOwnerSubscribed } = useFollowing() + const { t, lang } = useLocalize(); + const { author, isSessionLoaded, requireAuthentication } = useSession(); + const [authorSubs, setAuthorSubs] = createSignal< + Array + >([]); + const [subscriptionFilter, setSubscriptionFilter] = + createSignal("all"); + const [isFollowed, setIsFollowed] = createSignal(); + const isProfileOwner = createMemo(() => author()?.slug === props.author.slug); + const { setFollowing, isOwnerSubscribed } = useFollowing(); onMount(() => { - setAuthorSubs(props.following) - }) + setAuthorSubs(props.following); + }); createEffect(() => { - setIsFollowed(isOwnerSubscribed(props.author?.id)) - }) + setIsFollowed(isOwnerSubscribed(props.author?.id)); + }); const name = createMemo(() => { - if (lang() !== 'ru' && isCyrillic(props.author.name)) { - if (props.author.name === 'Дискурс') { - return 'Discours' + if (lang() !== "ru" && isCyrillic(props.author.name)) { + if (props.author.name === "Дискурс") { + return "Discours"; } - return translit(props.author.name) + return translit(props.author.name); } - return props.author.name - }) + return props.author.name; + }); // TODO: reimplement AuthorCard - const { changeSearchParams } = useRouter() + const { changeSearchParams } = useRouter(); const initChat = () => { // eslint-disable-next-line solid/reactivity requireAuthentication(() => { - openPage(router, 'inbox') + openPage(router, "inbox"); changeSearchParams({ initChat: props.author.id.toString(), - }) - }, 'discussions') - } + }); + }, "discussions"); + }; createEffect(() => { if (props.following) { - if (subscriptionFilter() === 'authors') { - setAuthorSubs(props.following.filter((s) => 'name' in s)) - } else if (subscriptionFilter() === 'topics') { - setAuthorSubs(props.following.filter((s) => 'title' in s)) - } else if (subscriptionFilter() === 'communities') { - setAuthorSubs(props.following.filter((s) => 'title' in s)) + if (subscriptionFilter() === "authors") { + setAuthorSubs(props.following.filter((s) => "name" in s)); + } else if (subscriptionFilter() === "topics") { + setAuthorSubs(props.following.filter((s) => "title" in s)); + } else if (subscriptionFilter() === "communities") { + setAuthorSubs(props.following.filter((s) => "title" in s)); } else { - setAuthorSubs(props.following) + setAuthorSubs(props.following); } } - }) + }); const handleFollowClick = () => { - const value = !isFollowed() + const value = !isFollowed(); requireAuthentication(() => { - setIsFollowed(value) - setFollowing(FollowingEntity.Author, props.author.slug, value) - }, 'subscribe') - } + setIsFollowed(value); + setFollowing(FollowingEntity.Author, props.author.slug, value); + }, "subscribe"); + }; const followButtonText = createMemo(() => { if (isOwnerSubscribed(props.author?.id)) { return ( <> - {t('Following')} - {t('Unfollow')} + + {t("Following")} + + + {t("Unfollow")} + - ) + ); } - return t('Follow') - }) + return t("Follow"); + }); return ( -
+
-
+
{name()}
@@ -130,11 +144,18 @@ export const AuthorCard = (props: Props) => { {(f) => ( - + )}
- {t('SubscriberWithCount', { count: props.followers.length ?? 0 })} + {t("SubscriberWithCount", { + count: props.followers.length ?? 0, + })}
@@ -143,33 +164,35 @@ export const AuthorCard = (props: Props) => { {(f) => { - if ('name' in f) { + if ("name" in f) { return ( - ) + ); } - if ('title' in f) { + if ("title" in f) { return ( - ) + ); } - return null + return null; }}
- {t('SubscriptionWithCount', { count: props?.following.length ?? 0 })} + {t("SubscriptionWithCount", { + count: props?.following.length ?? 0, + })}
@@ -184,12 +207,12 @@ export const AuthorCard = (props: Props) => { {(link) => ( - {link.startsWith('http') ? link : `https://${link}`} + {link.startsWith("http") ? link : `https://${link}`} )} @@ -211,8 +234,8 @@ export const AuthorCard = (props: Props) => { />
- + <> -

{t('Followers')}

+

{t("Followers")}

@@ -266,30 +300,61 @@ export const AuthorCard = (props: Props) => { - + <> -

{t('Subscriptions')}

+

{t("Subscriptions")}

    -
  • - - {props.following.length} -
  • -
  • - - {props.following.filter((s) => 'name' in s).length} + {props.following.length}
  • -
  • - - {props.following.filter((s) => 'title' in s).length} + {props.following.filter((s) => "name" in s).length} + +
  • +
  • + + + {props.following.filter((s) => "title" in s).length}
@@ -326,5 +391,5 @@ export const AuthorCard = (props: Props) => {
- ) -} + ); +}; diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 719f7b48..9a6c12fd 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -1,162 +1,197 @@ -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 { 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 -} -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, 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 [following, setFollowing] = createSignal>([]) - 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(() => { if (props.authorSlug) { if (session()?.user?.app_data?.profile?.slug === props.authorSlug) { - console.info('my own profile') - const { profile, authors, topics } = session().user.app_data - 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) - console.debug('[Author] expecting following data fetched') + const a = authorEntities()[props.authorSlug]; + setAuthor(a); + // TODO: add following data retrieval + 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), - ) + 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 (
@@ -176,42 +211,80 @@ export const AuthorView = (props: Props) => { }> <>
- +
-
+
-
- +
+
- {t('All posts rating')} - + {t("All posts rating")} +
@@ -221,7 +294,7 @@ export const AuthorView = (props: Props) => {
- +
@@ -230,22 +303,28 @@ export const AuthorView = (props: Props) => { class={styles.longBio} classList={{ [styles.longBioExpanded]: isBioExpanded() }} > -
(bioContainerRef.current = el)} innerHTML={author().about} /> +
(bioContainerRef.current = el)} + innerHTML={author().about} + />
- +
@@ -265,13 +344,18 @@ export const AuthorView = (props: Props) => {
- + - + @@ -280,21 +364,45 @@ export const AuthorView = (props: Props) => { 3}> - + - + - + {(page) => ( <> - + - + - + )} @@ -303,12 +411,12 @@ export const AuthorView = (props: Props) => {

- ) -} + ); +}; diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index 083e7978..d4db7857 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -1,59 +1,60 @@ -import { clsx } from 'clsx' -import { For, Show, createEffect, createSignal, onMount } from 'solid-js' +import { clsx } from "clsx"; +import { For, Show, createEffect, 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 { Author as AuthorType, Topic } from '../../../graphql/schema/core.gen' -import { SubscriptionFilter } from '../../../pages/types' -import { dummyFilter } from '../../../utils/dummyFilter' +import { useFollowing } from "../../../context/following"; +import { useLocalize } from "../../../context/localize"; +import { useSession } from "../../../context/session"; +import { apiClient } from "../../../graphql/client/core"; +import { Author, Topic } from "../../../graphql/schema/core.gen"; +import { SubscriptionFilter } from "../../../pages/types"; +import { dummyFilter } from "../../../utils/dummyFilter"; // TODO: refactor styles -import { isAuthor } from '../../../utils/isAuthor' -import { AuthorBadge } from '../../Author/AuthorBadge' -import { ProfileSettingsNavigation } from '../../Nav/ProfileSettingsNavigation' -import { TopicBadge } from '../../Topic/TopicBadge' -import { Loading } from '../../_shared/Loading' -import { SearchField } from '../../_shared/SearchField' +import { isAuthor } from "../../../utils/isAuthor"; +import { AuthorBadge } from "../../Author/AuthorBadge"; +import { ProfileSettingsNavigation } from "../../Nav/ProfileSettingsNavigation"; +import { TopicBadge } from "../../Topic/TopicBadge"; +import { Loading } from "../../_shared/Loading"; +import { SearchField } from "../../_shared/SearchField"; -import styles from '../../../pages/profile/Settings.module.scss' -import stylesSettings from '../../../styles/FeedSettings.module.scss' +import styles from "../../../pages/profile/Settings.module.scss"; +import stylesSettings from "../../../styles/FeedSettings.module.scss"; export const ProfileSubscriptions = () => { - const { t, lang } = useLocalize() - const { author, session } = useSession() - const { subscriptions } = useFollowing() - const [following, setFollowing] = (createSignal < Array < AuthorType) | (Topic >> []) - const [filtered, setFiltered] = (createSignal < Array < AuthorType) | (Topic >> []) - const [subscriptionFilter, setSubscriptionFilter] = createSignal < SubscriptionFilter > 'all' - const [searchQuery, setSearchQuery] = createSignal('') + const { t, lang } = useLocalize(); + const { author, session } = useSession(); + const { subscriptions } = useFollowing(); + const [following, setFollowing] = createSignal>([]); + const [filtered, setFiltered] = createSignal>([]); + const [subscriptionFilter, setSubscriptionFilter] = + createSignal("all"); + const [searchQuery, setSearchQuery] = createSignal(""); createEffect(() => { - const { authors, topics } = subscriptions + const { authors, topics } = subscriptions; if (authors || topics) { - const fdata = [...(authors || []), ...(topics || [])] - setFollowing(fdata) - if (subscriptionFilter() === 'authors') { - setFiltered(fdata.filter((s) => 'name' in s)) - } else if (subscriptionFilter() === 'topics') { - setFiltered(fdata.filter((s) => 'title' in s)) + const fdata = [...(authors || []), ...(topics || [])]; + setFollowing(fdata); + if (subscriptionFilter() === "authors") { + setFiltered(fdata.filter((s) => "name" in s)); + } else if (subscriptionFilter() === "topics") { + setFiltered(fdata.filter((s) => "title" in s)); } else { - setFiltered(fdata) + setFiltered(fdata); } } - }) + }); createEffect(() => { if (searchQuery()) { - setFiltered(dummyFilter(following(), searchQuery(), lang())) + setFiltered(dummyFilter(following(), searchQuery(), lang())); } - }) + }); return (
-
+
@@ -61,28 +62,54 @@ export const ProfileSubscriptions = () => {
-

{t('My subscriptions')}

-

{t('Here you can manage all your Discours subscriptions')}

+

{t("My subscriptions")}

+

+ {t("Here you can manage all your Discours subscriptions")} +

}>
    -
  • -
  • -
  • -
  • -
  • -
-
+
setSearchQuery(value)} class={styles.searchField} @@ -90,14 +117,22 @@ export const ProfileSubscriptions = () => { />
-
+
{(followingItem) => (
{isAuthor(followingItem) ? ( - + ) : ( - + )}
)} @@ -109,5 +144,5 @@ export const ProfileSubscriptions = () => {
- ) -} + ); +}; From 455006f6277be3a4e67c05ebfdf4a1e7dec663a0 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 18:19:43 +0300 Subject: [PATCH 23/36] fmt --- .../Author/AuthorCard/AuthorCard.tsx | 269 ++++++-------- src/components/Views/Author/Author.tsx | 336 +++++++----------- .../ProfileSubscriptions.tsx | 129 +++---- 3 files changed, 292 insertions(+), 442 deletions(-) diff --git a/src/components/Author/AuthorCard/AuthorCard.tsx b/src/components/Author/AuthorCard/AuthorCard.tsx index b6054a58..5fedd3e5 100644 --- a/src/components/Author/AuthorCard/AuthorCard.tsx +++ b/src/components/Author/AuthorCard/AuthorCard.tsx @@ -1,133 +1,119 @@ -import type { Author, Community } from "../../../graphql/schema/core.gen"; +import type { Author, Community } from '../../../graphql/schema/core.gen' -import { openPage, redirectPage } from "@nanostores/router"; -import { clsx } from "clsx"; -import { - For, - Show, - createEffect, - createMemo, - createSignal, - onMount, -} from "solid-js"; +import { openPage, redirectPage } from '@nanostores/router' +import { clsx } from 'clsx' +import { For, Show, createEffect, createMemo, createSignal, onMount } from 'solid-js' -import { useFollowing } from "../../../context/following"; -import { useLocalize } from "../../../context/localize"; -import { useSession } from "../../../context/session"; -import { FollowingEntity, Topic } from "../../../graphql/schema/core.gen"; -import { SubscriptionFilter } from "../../../pages/types"; -import { router, useRouter } from "../../../stores/router"; -import { isAuthor } from "../../../utils/isAuthor"; -import { translit } from "../../../utils/ru2en"; -import { isCyrillic } from "../../../utils/translate"; -import { SharePopup, getShareUrl } from "../../Article/SharePopup"; -import { Modal } from "../../Nav/Modal"; -import { TopicBadge } from "../../Topic/TopicBadge"; -import { Button } from "../../_shared/Button"; -import { ShowOnlyOnClient } from "../../_shared/ShowOnlyOnClient"; -import { AuthorBadge } from "../AuthorBadge"; -import { Userpic } from "../Userpic"; +import { useFollowing } from '../../../context/following' +import { useLocalize } from '../../../context/localize' +import { useSession } from '../../../context/session' +import { FollowingEntity, Topic } from '../../../graphql/schema/core.gen' +import { SubscriptionFilter } from '../../../pages/types' +import { router, useRouter } from '../../../stores/router' +import { isAuthor } from '../../../utils/isAuthor' +import { translit } from '../../../utils/ru2en' +import { isCyrillic } from '../../../utils/translate' +import { SharePopup, getShareUrl } from '../../Article/SharePopup' +import { Modal } from '../../Nav/Modal' +import { TopicBadge } from '../../Topic/TopicBadge' +import { Button } from '../../_shared/Button' +import { ShowOnlyOnClient } from '../../_shared/ShowOnlyOnClient' +import { AuthorBadge } from '../AuthorBadge' +import { Userpic } from '../Userpic' -import stylesButton from "../../_shared/Button/Button.module.scss"; -import styles from "./AuthorCard.module.scss"; +import stylesButton from '../../_shared/Button/Button.module.scss' +import styles from './AuthorCard.module.scss' type Props = { - author: Author; - followers?: Author[]; - following?: Array; -}; + author: Author + followers?: Author[] + following?: Array +} export const AuthorCard = (props: Props) => { - const { t, lang } = useLocalize(); - const { author, isSessionLoaded, requireAuthentication } = useSession(); - const [authorSubs, setAuthorSubs] = createSignal< - Array - >([]); - const [subscriptionFilter, setSubscriptionFilter] = - createSignal("all"); - const [isFollowed, setIsFollowed] = createSignal(); - const isProfileOwner = createMemo(() => author()?.slug === props.author.slug); - const { setFollowing, isOwnerSubscribed } = useFollowing(); + const { t, lang } = useLocalize() + const { author, isSessionLoaded, requireAuthentication } = useSession() + const [authorSubs, setAuthorSubs] = createSignal>([]) + const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') + const [isFollowed, setIsFollowed] = createSignal() + const isProfileOwner = createMemo(() => author()?.slug === props.author.slug) + const { setFollowing, isOwnerSubscribed } = useFollowing() onMount(() => { - setAuthorSubs(props.following); - }); + setAuthorSubs(props.following) + }) createEffect(() => { - setIsFollowed(isOwnerSubscribed(props.author?.id)); - }); + setIsFollowed(isOwnerSubscribed(props.author?.id)) + }) const name = createMemo(() => { - if (lang() !== "ru" && isCyrillic(props.author.name)) { - if (props.author.name === "Дискурс") { - return "Discours"; + if (lang() !== 'ru' && isCyrillic(props.author.name)) { + if (props.author.name === 'Дискурс') { + return 'Discours' } - return translit(props.author.name); + return translit(props.author.name) } - return props.author.name; - }); + return props.author.name + }) // TODO: reimplement AuthorCard - const { changeSearchParams } = useRouter(); + const { changeSearchParams } = useRouter() const initChat = () => { // eslint-disable-next-line solid/reactivity requireAuthentication(() => { - openPage(router, "inbox"); + openPage(router, 'inbox') changeSearchParams({ initChat: props.author.id.toString(), - }); - }, "discussions"); - }; + }) + }, 'discussions') + } createEffect(() => { if (props.following) { - if (subscriptionFilter() === "authors") { - setAuthorSubs(props.following.filter((s) => "name" in s)); - } else if (subscriptionFilter() === "topics") { - setAuthorSubs(props.following.filter((s) => "title" in s)); - } else if (subscriptionFilter() === "communities") { - setAuthorSubs(props.following.filter((s) => "title" in s)); + if (subscriptionFilter() === 'authors') { + setAuthorSubs(props.following.filter((s) => 'name' in s)) + } else if (subscriptionFilter() === 'topics') { + setAuthorSubs(props.following.filter((s) => 'title' in s)) + } else if (subscriptionFilter() === 'communities') { + setAuthorSubs(props.following.filter((s) => 'title' in s)) } else { - setAuthorSubs(props.following); + setAuthorSubs(props.following) } } - }); + }) const handleFollowClick = () => { - const value = !isFollowed(); + const value = !isFollowed() requireAuthentication(() => { - setIsFollowed(value); - setFollowing(FollowingEntity.Author, props.author.slug, value); - }, "subscribe"); - }; + setIsFollowed(value) + setFollowing(FollowingEntity.Author, props.author.slug, value) + }, 'subscribe') + } const followButtonText = createMemo(() => { if (isOwnerSubscribed(props.author?.id)) { return ( <> - - {t("Following")} - - - {t("Unfollow")} - + {t('Following')} + {t('Unfollow')} - ); + ) } - return t("Follow"); - }); + return t('Follow') + }) return ( -
+
-
+
{name()}
@@ -144,16 +130,11 @@ export const AuthorCard = (props: Props) => { {(f) => ( - + )}
- {t("SubscriberWithCount", { + {t('SubscriberWithCount', { count: props.followers.length ?? 0, })}
@@ -164,33 +145,33 @@ export const AuthorCard = (props: Props) => {
{(f) => { - if ("name" in f) { + if ('name' in f) { return ( - ); + ) } - if ("title" in f) { + if ('title' in f) { return ( - ); + ) } - return null; + return null }}
- {t("SubscriptionWithCount", { + {t('SubscriptionWithCount', { count: props?.following.length ?? 0, })}
@@ -207,12 +188,12 @@ export const AuthorCard = (props: Props) => { {(link) => (
- {link.startsWith("http") ? link : `https://${link}`} + {link.startsWith('http') ? link : `https://${link}`} )} @@ -234,8 +215,8 @@ export const AuthorCard = (props: Props) => { />
- + <> -

{t("Followers")}

+

{t('Followers')}

@@ -300,61 +272,42 @@ export const AuthorCard = (props: Props) => { - + <> -

{t("Subscriptions")}

+

{t('Subscriptions')}

  • - + {props.following.length} +
  • +
  • + - {props.following.length} + {props.following.filter((s) => 'name' in s).length}
  • - - {props.following.filter((s) => "name" in s).length} - -
  • -
  • - - - {props.following.filter((s) => "title" in s).length} + {props.following.filter((s) => 'title' in s).length}
@@ -391,5 +344,5 @@ export const AuthorCard = (props: Props) => {
- ); -}; + ) +} diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 9a6c12fd..0c6a958a 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -1,197 +1,168 @@ -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(() => { if (props.authorSlug) { if (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, - ), - ); + 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 (
@@ -211,80 +182,64 @@ export const AuthorView = (props: Props) => { }> <>
- +
-
+
-
- +
+
- {t("All posts rating")} - + {t('All posts rating')} +
@@ -294,7 +249,7 @@ export const AuthorView = (props: Props) => {
- +
@@ -303,28 +258,22 @@ export const AuthorView = (props: Props) => { class={styles.longBio} classList={{ [styles.longBioExpanded]: isBioExpanded() }} > -
(bioContainerRef.current = el)} - innerHTML={author().about} - /> +
(bioContainerRef.current = el)} innerHTML={author().about} />
- +
@@ -344,18 +293,13 @@ export const AuthorView = (props: Props) => {
- + - + @@ -364,45 +308,21 @@ export const AuthorView = (props: Props) => { 3}> - + - + - + {(page) => ( <> - + - + - + )} @@ -411,12 +331,12 @@ export const AuthorView = (props: Props) => {

- ); -}; + ) +} diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index d4db7857..51f27325 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -1,60 +1,59 @@ -import { clsx } from "clsx"; -import { For, Show, createEffect, createSignal, onMount } from "solid-js"; +import { clsx } from 'clsx' +import { For, Show, createEffect, 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 { Author, Topic } from "../../../graphql/schema/core.gen"; -import { SubscriptionFilter } from "../../../pages/types"; -import { dummyFilter } from "../../../utils/dummyFilter"; +import { useFollowing } from '../../../context/following' +import { useLocalize } from '../../../context/localize' +import { useSession } from '../../../context/session' +import { apiClient } from '../../../graphql/client/core' +import { Author, Topic } from '../../../graphql/schema/core.gen' +import { SubscriptionFilter } from '../../../pages/types' +import { dummyFilter } from '../../../utils/dummyFilter' // TODO: refactor styles -import { isAuthor } from "../../../utils/isAuthor"; -import { AuthorBadge } from "../../Author/AuthorBadge"; -import { ProfileSettingsNavigation } from "../../Nav/ProfileSettingsNavigation"; -import { TopicBadge } from "../../Topic/TopicBadge"; -import { Loading } from "../../_shared/Loading"; -import { SearchField } from "../../_shared/SearchField"; +import { isAuthor } from '../../../utils/isAuthor' +import { AuthorBadge } from '../../Author/AuthorBadge' +import { ProfileSettingsNavigation } from '../../Nav/ProfileSettingsNavigation' +import { TopicBadge } from '../../Topic/TopicBadge' +import { Loading } from '../../_shared/Loading' +import { SearchField } from '../../_shared/SearchField' -import styles from "../../../pages/profile/Settings.module.scss"; -import stylesSettings from "../../../styles/FeedSettings.module.scss"; +import styles from '../../../pages/profile/Settings.module.scss' +import stylesSettings from '../../../styles/FeedSettings.module.scss' export const ProfileSubscriptions = () => { - const { t, lang } = useLocalize(); - const { author, session } = useSession(); - const { subscriptions } = useFollowing(); - const [following, setFollowing] = createSignal>([]); - const [filtered, setFiltered] = createSignal>([]); - const [subscriptionFilter, setSubscriptionFilter] = - createSignal("all"); - const [searchQuery, setSearchQuery] = createSignal(""); + const { t, lang } = useLocalize() + const { author, session } = useSession() + const { subscriptions } = useFollowing() + const [following, setFollowing] = createSignal>([]) + const [filtered, setFiltered] = createSignal>([]) + const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') + const [searchQuery, setSearchQuery] = createSignal('') createEffect(() => { - const { authors, topics } = subscriptions; + const { authors, topics } = subscriptions if (authors || topics) { - const fdata = [...(authors || []), ...(topics || [])]; - setFollowing(fdata); - if (subscriptionFilter() === "authors") { - setFiltered(fdata.filter((s) => "name" in s)); - } else if (subscriptionFilter() === "topics") { - setFiltered(fdata.filter((s) => "title" in s)); + const fdata = [...(authors || []), ...(topics || [])] + setFollowing(fdata) + if (subscriptionFilter() === 'authors') { + setFiltered(fdata.filter((s) => 'name' in s)) + } else if (subscriptionFilter() === 'topics') { + setFiltered(fdata.filter((s) => 'title' in s)) } else { - setFiltered(fdata); + setFiltered(fdata) } } - }); + }) createEffect(() => { if (searchQuery()) { - setFiltered(dummyFilter(following(), searchQuery(), lang())); + setFiltered(dummyFilter(following(), searchQuery(), lang())) } - }); + }) return (
-
+
@@ -62,54 +61,40 @@ export const ProfileSubscriptions = () => {
-

{t("My subscriptions")}

-

- {t("Here you can manage all your Discours subscriptions")} -

+

{t('My subscriptions')}

+

{t('Here you can manage all your Discours subscriptions')}

}>
  • -
  • -
  • -
-
+
setSearchQuery(value)} class={styles.searchField} @@ -117,22 +102,14 @@ export const ProfileSubscriptions = () => { />
-
+
{(followingItem) => (
{isAuthor(followingItem) ? ( - + ) : ( - + )}
)} @@ -144,5 +121,5 @@ export const ProfileSubscriptions = () => {
- ); -}; + ) +} From 499341baeaf17f857a1aae082a9f7675a9a0bbb9 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Mon, 8 Apr 2024 18:28:08 +0300 Subject: [PATCH 24/36] fix syule types --- src/components/Nav/Header/Header.module.scss | 2 +- src/components/Nav/HeaderAuth.tsx | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/Nav/Header/Header.module.scss b/src/components/Nav/Header/Header.module.scss index 660a2245..010a8164 100644 --- a/src/components/Nav/Header/Header.module.scss +++ b/src/components/Nav/Header/Header.module.scss @@ -8,7 +8,7 @@ z-index: 10003; .wide-container { - background: #fff; + background: var(--background-color); @include media-breakpoint-down(lg) { padding: 0 divide($container-padding-x, 2); diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index 2b6b1ea3..8ddff9df 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -14,12 +14,9 @@ import { Icon } from '../_shared/Icon' import { Popover } from '../_shared/Popover' import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient' -import { ProfilePopup } from './ProfilePopup' - -import { useSnackbar } from '../../context/snackbar' import { Popup } from '../_shared/Popup' -import { VotersList } from '../_shared/VotersList' import styles from './Header/Header.module.scss' +import { ProfilePopup } from './ProfilePopup' type Props = { setIsProfilePopupVisible: (value: boolean) => void From 78cde31943c801e2971e2a3b0bc65f93aa5be8ec Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Mon, 15 Apr 2024 07:43:48 +0300 Subject: [PATCH 25/36] Swiper (init with promise) --- src/components/_shared/SolidSwiper/ImageSwiper.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/_shared/SolidSwiper/ImageSwiper.tsx b/src/components/_shared/SolidSwiper/ImageSwiper.tsx index 1de1fe65..d018632c 100644 --- a/src/components/_shared/SolidSwiper/ImageSwiper.tsx +++ b/src/components/_shared/SolidSwiper/ImageSwiper.tsx @@ -49,12 +49,17 @@ export const ImageSwiper = (props: Props) => { ) onMount(async () => { + console.log("!!! onMount:"); const { register } = await import('swiper/element/bundle') register() SwiperCore.use([Pagination, Navigation, Manipulation]) - mainSwipeRef.current?.swiper?.on('slideChange', handleSlideChange) + while (!mainSwipeRef.current || !mainSwipeRef.current.swiper) { + await new Promise(resolve => setTimeout(resolve, 10)); // wait 10 ms + } + mainSwipeRef.current.swiper.on('slideChange', handleSlideChange); }) + onMount(() => { const updateDirection = () => { const width = window.innerWidth From e3a2aaf73a6f6ff9a3f474193da619de430e26b2 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Mon, 15 Apr 2024 15:39:34 +0300 Subject: [PATCH 26/36] Load user profile --- src/components/Views/Author/Author.tsx | 237 +++++++++--------- .../_shared/SolidSwiper/ImageSwiper.tsx | 1 - src/stores/zine/authors.ts | 2 +- 3 files changed, 120 insertions(+), 120 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 0c6a958a..651ee47d 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -1,168 +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(() => { - if (props.authorSlug) { - if (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]) - } + createEffect(async () => { + await loadAuthor({ slug: props.authorSlug }); + }) + 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]); } 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 (
@@ -184,20 +185,20 @@ export const AuthorView = (props: Props) => {
-
+
-
+
- {t('All posts rating')} + {t("All posts rating")}
@@ -249,7 +250,7 @@ export const AuthorView = (props: Props) => {
- +
@@ -263,17 +264,17 @@ export const AuthorView = (props: Props) => {
- +
@@ -293,7 +294,7 @@ export const AuthorView = (props: Props) => {
- + @@ -331,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 d018632c..9653b449 100644 --- a/src/components/_shared/SolidSwiper/ImageSwiper.tsx +++ b/src/components/_shared/SolidSwiper/ImageSwiper.tsx @@ -49,7 +49,6 @@ export const ImageSwiper = (props: Props) => { ) onMount(async () => { - console.log("!!! onMount:"); const { register } = await import('swiper/element/bundle') register() SwiperCore.use([Pagination, Navigation, Manipulation]) diff --git a/src/stores/zine/authors.ts b/src/stores/zine/authors.ts index 131b70c6..33861246 100644 --- a/src/stores/zine/authors.ts +++ b/src/stores/zine/authors.ts @@ -1,5 +1,5 @@ import { createLazyMemo } from '@solid-primitives/memo' -import { 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' From 6e48e644972fab5b2ae762178f40f8c59975fbd3 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 15 Apr 2024 21:01:00 +0300 Subject: [PATCH 27/36] -npm-run-format --- .github/workflows/node-ci.yml | 2 +- src/components/Views/Author/Author.tsx | 232 +++++++++--------- .../_shared/SolidSwiper/ImageSwiper.tsx | 5 +- src/stores/zine/authors.ts | 2 +- 4 files changed, 120 insertions(+), 121 deletions(-) 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' From 5ddbb0dd1b8dfe1267c2cd21cfe7a46b89a75411 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 15 Apr 2024 21:02:58 +0300 Subject: [PATCH 28/36] biome-ignore --- biome.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biome.json b/biome.json index ba7464a5..ca4262bb 100644 --- a/biome.json +++ b/biome.json @@ -2,7 +2,7 @@ "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", "files": { "include": ["*.tsx", "*.ts", "*.js", "*.json"], - "ignore": ["./dist", "./node_modules", ".husky", "docs", "gen", "*.d.ts"] + "ignore": ["./dist", "./node_modules", ".husky", "docs", "gen", "*.gen.ts", "*.d.ts"] }, "vcs": { "defaultBranch": "dev", From bd4fedc6c727806c72feb1cc469bff4f18b5d2d3 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 16 Apr 2024 07:01:18 +0300 Subject: [PATCH 29/36] preloaded-author-fix --- src/components/Views/Author/Author.tsx | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 870d4e5c..22fdf134 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -53,32 +53,26 @@ export const AuthorView = (props: Props) => { const [commented, setCommented] = createSignal() const modal = MODALS[searchParams().m] - // current author createEffect(async () => { - await loadAuthor({ slug: props.authorSlug }) - }) - createEffect(() => { if (props.authorSlug && session()?.user?.app_data?.profile?.slug === props.authorSlug) { - console.info('my own profile') + console.info('preloaded 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) - // TODO: add following data retrieval - console.debug('[Author] expecting following data fetched') - } catch (error) { - console.debug(error) - } } }) createEffect(async () => { - if (author()?.id && !author().stat) { - const a = await loadAuthor({ slug: '', author_id: author().id }) + if(Object.keys(authorEntities()).includes(props.authorSlug) && !author()?.id) { + // use preloaded author + const a = authorEntities()[props.authorSlug] + setAuthor(a) + console.debug('[AuthorView] preloaded author:', a) + } else if(props.authorSlug || (author()?.id && !author().stat)) { + // load author + const a = await loadAuthor({ slug: props.authorSlug, author_id: author()?.id }) + setAuthor(a) console.debug('[AuthorView] loaded author:', a) } }) From f7c33c167a8cd9020ba0062b8d736d6e09332f1e Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 16 Apr 2024 07:03:05 +0300 Subject: [PATCH 30/36] fmt --- src/components/Views/Author/Author.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 22fdf134..b59c3da1 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -64,12 +64,12 @@ export const AuthorView = (props: Props) => { }) createEffect(async () => { - if(Object.keys(authorEntities()).includes(props.authorSlug) && !author()?.id) { + if (Object.keys(authorEntities()).includes(props.authorSlug) && !author()?.id) { // use preloaded author const a = authorEntities()[props.authorSlug] setAuthor(a) console.debug('[AuthorView] preloaded author:', a) - } else if(props.authorSlug || (author()?.id && !author().stat)) { + } else if (props.authorSlug || (author()?.id && !author().stat)) { // load author const a = await loadAuthor({ slug: props.authorSlug, author_id: author()?.id }) setAuthor(a) From f2012bca18b09034b0bb952b9ce821df7f2cae00 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 16 Apr 2024 07:07:36 +0300 Subject: [PATCH 31/36] load-fix --- src/components/Views/Author/Author.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index b59c3da1..78bcd4ac 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -69,7 +69,7 @@ export const AuthorView = (props: Props) => { const a = authorEntities()[props.authorSlug] setAuthor(a) console.debug('[AuthorView] preloaded author:', a) - } else if (props.authorSlug || (author()?.id && !author().stat)) { + } else if (props.authorSlug && !author().stat) { // load author const a = await loadAuthor({ slug: props.authorSlug, author_id: author()?.id }) setAuthor(a) From 6fbe9603feaa4b3176e81dff4083c8611f5cc2e9 Mon Sep 17 00:00:00 2001 From: Untone Date: Tue, 16 Apr 2024 07:08:20 +0300 Subject: [PATCH 32/36] conditional --- src/components/Views/Author/Author.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 78bcd4ac..4784197a 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -69,7 +69,7 @@ export const AuthorView = (props: Props) => { const a = authorEntities()[props.authorSlug] setAuthor(a) console.debug('[AuthorView] preloaded author:', a) - } else if (props.authorSlug && !author().stat) { + } else if (props.authorSlug && !author()?.stat) { // load author const a = await loadAuthor({ slug: props.authorSlug, author_id: author()?.id }) setAuthor(a) From 69fc0ffd0704571706411c3ddd160e67dc5fed0b Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 17 Apr 2024 16:44:53 +0300 Subject: [PATCH 33/36] less-code --- src/components/Views/Author/Author.tsx | 37 +++++++------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 4784197a..ed0645d5 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -53,8 +53,10 @@ export const AuthorView = (props: Props) => { const [commented, setCommented] = createSignal() const modal = MODALS[searchParams().m] - createEffect(async () => { - if (props.authorSlug && session()?.user?.app_data?.profile?.slug === props.authorSlug) { + const [sessionChecked, setSessionChecked] = createSignal(false) + createEffect(() => { + if (!sessionChecked() && props.authorSlug && session()?.user?.app_data?.profile?.slug === props.authorSlug) { + setSessionChecked(true) console.info('preloaded my own profile') const { profile, authors, topics } = session().user.app_data setFollowers(myFollowers) @@ -63,35 +65,22 @@ export const AuthorView = (props: Props) => { } }) - createEffect(async () => { - if (Object.keys(authorEntities()).includes(props.authorSlug) && !author()?.id) { - // use preloaded author - const a = authorEntities()[props.authorSlug] - setAuthor(a) - console.debug('[AuthorView] preloaded author:', a) - } else if (props.authorSlug && !author()?.stat) { - // load author - const a = await loadAuthor({ slug: props.authorSlug, author_id: author()?.id }) - setAuthor(a) - console.debug('[AuthorView] loaded author:', a) - } - }) - const bioContainerRef: { current: HTMLDivElement } = { current: null } const bioWrapperRef: { current: HTMLDivElement } = { current: null } const fetchData = async (slug) => { try { - const [subscriptionsResult, followersResult] = await Promise.all([ + const [subscriptionsResult, followersResult, authorResult] = await Promise.all([ apiClient.getAuthorFollows({ slug }), apiClient.getAuthorFollowers({ slug }), + loadAuthor({ slug }) ]) - const { authors, topics } = subscriptionsResult + setAuthor(authorResult) setFollowing([...(authors || []), ...(topics || [])]) setFollowers(followersResult || []) - console.info('[components.Author] following data loaded') + console.info('[components.Author] data loaded') } catch (error) { console.error('[components.Author] fetch error', error) } @@ -103,14 +92,6 @@ export const AuthorView = (props: Props) => { } } - onMount(() => { - fetchData(props.authorSlug) - - if (!modal) { - hideModal() - } - }) - const loadMore = async () => { saveScrollPosition() const { hasMore } = await loadShouts({ @@ -123,7 +104,9 @@ export const AuthorView = (props: Props) => { } onMount(() => { + if (!modal) hideModal() checkBioHeight() + fetchData(props.authorSlug) // pagination if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) { From 0f28fe891a41212a619c93a41e1c4ed5f18a6a59 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 17 Apr 2024 18:47:24 +0300 Subject: [PATCH 34/36] post-oauth-fix --- src/components/Views/Author/Author.tsx | 21 ++++++++++++++------- src/context/following.tsx | 11 +++++++---- src/context/session.tsx | 11 +++++++---- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index ed0645d5..0a351f0c 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -55,13 +55,20 @@ export const AuthorView = (props: Props) => { const [sessionChecked, setSessionChecked] = createSignal(false) createEffect(() => { - if (!sessionChecked() && props.authorSlug && session()?.user?.app_data?.profile?.slug === props.authorSlug) { + if ( + !sessionChecked() && + props.authorSlug && + session()?.user?.app_data?.profile?.slug === props.authorSlug + ) { setSessionChecked(true) - console.info('preloaded my own profile') - const { profile, authors, topics } = session().user.app_data - setFollowers(myFollowers) - setAuthor(profile) - setFollowing([...authors, ...topics]) + const appdata = session()?.user.app_data + if (appdata) { + console.info('preloaded my own profile') + const { authors, followers, topics } = appdata + setFollowers(myFollowers) + setAuthor(profile) + setFollowing([...authors, ...topics]) + } } }) @@ -73,7 +80,7 @@ export const AuthorView = (props: Props) => { const [subscriptionsResult, followersResult, authorResult] = await Promise.all([ apiClient.getAuthorFollows({ slug }), apiClient.getAuthorFollowers({ slug }), - loadAuthor({ slug }) + loadAuthor({ slug }), ]) const { authors, topics } = subscriptionsResult setAuthor(authorResult) diff --git a/src/context/following.tsx b/src/context/following.tsx index ad93eaaf..fc92565e 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -80,10 +80,13 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { createEffect(() => { if (author()) { try { - const { authors, followers, topics } = session().user.app_data - setSubscriptions({ authors, topics }) - setFollowers(followers) - if (!authors) fetchData() + const appdata = session()?.user.app_data + if (appdata) { + const { authors, followers, topics } = appdata + setSubscriptions({ authors, topics }) + setFollowers(followers) + if (!authors) fetchData() + } } catch (e) { console.error(e) } diff --git a/src/context/session.tsx b/src/context/session.tsx index 67bd5a93..fa068bc8 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -220,10 +220,13 @@ export const SessionProvider = (props: { } try { - const { profile } = session().user.app_data - setAuthor(profile) - addAuthors([profile]) - if (!profile) loadAuthor() + const appdata = session()?.user.app_data + if (appdata) { + const { profile } = appdata + setAuthor(profile) + addAuthors([profile]) + if (!profile) loadAuthor() + } } catch (e) { console.error(e) } From 36970c03c4fa9845601a0edca707cba3e5fe4134 Mon Sep 17 00:00:00 2001 From: Untone Date: Wed, 17 Apr 2024 19:26:26 +0300 Subject: [PATCH 35/36] profile-fix --- src/components/Views/Author/Author.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 0a351f0c..ad3840d9 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -64,7 +64,7 @@ export const AuthorView = (props: Props) => { const appdata = session()?.user.app_data if (appdata) { console.info('preloaded my own profile') - const { authors, followers, topics } = appdata + const { authors, profile, topics } = appdata setFollowers(myFollowers) setAuthor(profile) setFollowing([...authors, ...topics]) From 16e3e753813f8497b4ee085dbade0e84130c23dd Mon Sep 17 00:00:00 2001 From: Ilya Y <75578537+ilya-bkv@users.noreply.github.com> Date: Thu, 18 Apr 2024 16:34:07 +0300 Subject: [PATCH 36/36] Add hash navigation in slider (#440) Sliders with search params --- src/components/Article/FullArticle.tsx | 1 + .../_shared/SolidSwiper/ImageSwiper.tsx | 26 +++++++++++++++---- .../_shared/SolidSwiper/Swiper.module.scss | 6 ++++- src/stores/router.ts | 4 +-- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index f855f170..6d9a670f 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -54,6 +54,7 @@ type IframeSize = { export type ArticlePageSearchParams = { scrollTo: 'comments' commentId: string + slide?: string } const scrollTo = (el: HTMLElement) => { diff --git a/src/components/_shared/SolidSwiper/ImageSwiper.tsx b/src/components/_shared/SolidSwiper/ImageSwiper.tsx index 888a23c3..674ac701 100644 --- a/src/components/_shared/SolidSwiper/ImageSwiper.tsx +++ b/src/components/_shared/SolidSwiper/ImageSwiper.tsx @@ -1,7 +1,7 @@ import { clsx } from 'clsx' import { For, Show, createEffect, createSignal, on, onCleanup, onMount } from 'solid-js' import SwiperCore from 'swiper' -import { Manipulation, Navigation, Pagination } from 'swiper/modules' +import { HashNavigation, Manipulation, Navigation, Pagination } from 'swiper/modules' import { throttle } from 'throttle-debounce' import { MediaItem } from '../../../pages/types' @@ -12,6 +12,8 @@ import { Lightbox } from '../Lightbox' import { SwiperRef } from './swiper' +import { useRouter } from '../../../stores/router' +import { ArticlePageSearchParams } from '../../Article/FullArticle' import styles from './Swiper.module.scss' type Props = { @@ -31,10 +33,13 @@ export const ImageSwiper = (props: Props) => { const [slideIndex, setSlideIndex] = createSignal(0) const [isMobileView, setIsMobileView] = createSignal(false) const [selectedImage, setSelectedImage] = createSignal('') + const { searchParams, changeSearchParams } = useRouter() const handleSlideChange = () => { - thumbSwipeRef.current.swiper.slideTo(mainSwipeRef.current.swiper.activeIndex) - setSlideIndex(mainSwipeRef.current.swiper.activeIndex) + const activeIndex = mainSwipeRef.current.swiper.activeIndex + thumbSwipeRef.current.swiper.slideTo(activeIndex) + setSlideIndex(activeIndex) + changeSearchParams({ slide: `${activeIndex + 1}` }) } createEffect( @@ -51,11 +56,19 @@ export const ImageSwiper = (props: Props) => { onMount(async () => { const { register } = await import('swiper/element/bundle') register() - SwiperCore.use([Pagination, Navigation, Manipulation]) + SwiperCore.use([Pagination, Navigation, Manipulation, HashNavigation]) while (!mainSwipeRef.current || !mainSwipeRef.current.swiper) { await new Promise((resolve) => setTimeout(resolve, 10)) // wait 10 ms } mainSwipeRef.current.swiper.on('slideChange', handleSlideChange) + const initialSlide = parseInt(searchParams().slide) - 1 + if (initialSlide && !Number.isNaN(initialSlide) && initialSlide < props.images.length) { + mainSwipeRef.current.swiper.slideTo(initialSlide, 0) + } else { + changeSearchParams({ slide: '1' }) + } + + mainSwipeRef.current.swiper.init() }) onMount(() => { @@ -106,6 +119,9 @@ export const ImageSwiper = (props: Props) => { watch-slides-visibility={true} direction={'horizontal'} slides-per-group-auto={true} + hash-navigation={{ + watchState: true, + }} > {(slide, index) => ( @@ -152,7 +168,7 @@ export const ImageSwiper = (props: Props) => { {(slide, index) => ( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - +
{slide.title}
diff --git a/src/components/_shared/SolidSwiper/Swiper.module.scss b/src/components/_shared/SolidSwiper/Swiper.module.scss index b8e5b990..f3f182e8 100644 --- a/src/components/_shared/SolidSwiper/Swiper.module.scss +++ b/src/components/_shared/SolidSwiper/Swiper.module.scss @@ -135,9 +135,13 @@ .counter { @include font-size(1.2rem); + @include media-breakpoint-up(sm) { + top: 477px; + } + position: absolute; z-index: 2; - top: 477px; + top: 276px; right: 0; font-weight: 600; padding: 0.2rem 0.8rem; diff --git a/src/stores/router.ts b/src/stores/router.ts index be197bd1..8be3b78c 100644 --- a/src/stores/router.ts +++ b/src/stores/router.ts @@ -114,8 +114,8 @@ const handleClientRouteLinkClick = async (event) => { } if (url.hash) { - scrollToHash(url.hash) - return + // scrollToHash(url.hash) + // return } window.scrollTo({