From 5102b502b15eb07ace7fb41781fc03b30b96c46f Mon Sep 17 00:00:00 2001 From: bniwredyc Date: Wed, 29 Mar 2023 19:02:31 +0200 Subject: [PATCH 1/7] router fix --- src/components/Article/FullArticle.tsx | 2 +- src/stores/router.ts | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index a350b1fb..7bc6c174 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -270,7 +270,7 @@ export const FullArticle = (props: ArticleProps) => { )} -
+
{ if (url.origin === location.origin) { event.preventDefault() + if (url.pathname) { + routerStore.open(url.pathname) + } + + if (url.search) { + const params = Object.fromEntries(new URLSearchParams(url.search)) + searchParamsStore.open(params) + } + if (url.hash) { let selector = url.hash @@ -79,10 +88,6 @@ const handleClientRouteLinkClick = (event) => { return } - routerStore.open(url.pathname) - const params = Object.fromEntries(new URLSearchParams(url.search)) - searchParamsStore.open(params) - window.scrollTo({ top: 0, left: 0 From 492dabb7b92966fb2a3170694dc8c63b41746abd Mon Sep 17 00:00:00 2001 From: ilia tapazukk Date: Sat, 1 Apr 2023 04:20:14 +0000 Subject: [PATCH 2/7] [161] scroll to comments --- src/components/Article/FullArticle.tsx | 10 ++++++++-- src/components/Feed/Card.tsx | 15 +++++++++++++-- src/components/Nav/ProfilePopup.tsx | 21 ++++++++++++++++++--- src/components/Views/Author.tsx | 4 ++-- src/graphql/query/articles-load-by.ts | 1 + 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index a350b1fb..702d7c48 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -2,7 +2,7 @@ import { capitalize, formatDate } from '../../utils' import './Full.scss' import { Icon } from '../_shared/Icon' import { AuthorCard } from '../Author/Card' -import { createMemo, createSignal, For, Match, onMount, Show, Switch } from 'solid-js' +import { createEffect, createMemo, createSignal, For, Match, onMount, Show, Switch } from 'solid-js' import type { Author, Shout } from '../../graphql/types.gen' import MD from './MD' import { SharePopup } from './SharePopup' @@ -16,7 +16,7 @@ import { useSession } from '../../context/session' import VideoPlayer from './VideoPlayer' import Slider from '../_shared/Slider' import { getPagePath } from '@nanostores/router' -import { router } from '../../stores/router' +import { router, useRouter } from '../../stores/router' import { useReactions } from '../../context/reactions' import { Title } from '@solidjs/meta' import { useLocalize } from '../../context/localize' @@ -112,6 +112,12 @@ export const FullArticle = (props: ArticleProps) => { } commentsRef.scrollIntoView({ behavior: 'smooth' }) } + const { searchParams } = useRouter() + createEffect(() => { + if (searchParams()?.scrollTo === 'comments') { + scrollToComments() + } + }) return ( <> diff --git a/src/components/Feed/Card.tsx b/src/components/Feed/Card.tsx index f6630608..29515264 100644 --- a/src/components/Feed/Card.tsx +++ b/src/components/Feed/Card.tsx @@ -12,7 +12,12 @@ import stylesHeader from '../Nav/Header.module.scss' import { getDescription } from '../../utils/meta' import { FeedArticlePopup } from './FeedArticlePopup' import { useLocalize } from '../../context/localize' +import { openPage } from '@nanostores/router' +import { router, useRouter } from '../../stores/router' +type ArticleSearchParams = { + scrollTo: 'comments' +} interface ArticleCardProps { settings?: { noicon?: boolean @@ -75,6 +80,12 @@ export const ArticleCard = (props: ArticleCardProps) => { const { cover, layout, slug, authors, stat, body } = props.article + const { changeSearchParam } = useRouter() + const scrollToComments = () => { + openPage(router, 'article', { slug: slug }) + changeSearchParam('scrollTo', 'comments') + } + return (
{
diff --git a/src/components/Nav/ProfilePopup.tsx b/src/components/Nav/ProfilePopup.tsx index 9dd0e135..1d5bfd5b 100644 --- a/src/components/Nav/ProfilePopup.tsx +++ b/src/components/Nav/ProfilePopup.tsx @@ -2,9 +2,10 @@ import { useSession } from '../../context/session' import type { PopupProps } from '../_shared/Popup' import { Popup } from '../_shared/Popup' import styles from '../_shared/Popup/Popup.module.scss' -import { getPagePath } from '@nanostores/router' -import { router } from '../../stores/router' +import { getPagePath, openPage } from '@nanostores/router' +import { router, useRouter } from '../../stores/router' import { useLocalize } from '../../context/localize' +import type { AuthorPageSearchParams } from '../Views/Author' type ProfilePopupProps = Omit @@ -15,6 +16,12 @@ export const ProfilePopup = (props: ProfilePopupProps) => { } = useSession() const { t } = useLocalize() + const { changeSearchParam } = useRouter() + + const openAuthorComments = () => { + openPage(router, 'author', { slug: userSlug() }) + changeSearchParam('by', 'commented') + } return ( @@ -29,7 +36,15 @@ export const ProfilePopup = (props: ProfilePopupProps) => { {t('Subscriptions')}
  • - {t('Comments')} + { + event.preventDefault() + openAuthorComments() + }} + > + {t('Comments')} +
  • {t('Bookmarks')} diff --git a/src/components/Views/Author.tsx b/src/components/Views/Author.tsx index f0de8463..535c915a 100644 --- a/src/components/Views/Author.tsx +++ b/src/components/Views/Author.tsx @@ -26,7 +26,7 @@ type AuthorProps = { authorSlug: string } -type AuthorPageSearchParams = { +export type AuthorPageSearchParams = { by: '' | 'viewed' | 'rating' | 'commented' | 'recent' | 'followed' | 'about' | 'popular' } @@ -131,7 +131,7 @@ export const AuthorView = (props: AuthorProps) => { */}
  • diff --git a/src/graphql/query/articles-load-by.ts b/src/graphql/query/articles-load-by.ts index 4baad70a..b7929c2c 100644 --- a/src/graphql/query/articles-load-by.ts +++ b/src/graphql/query/articles-load-by.ts @@ -37,6 +37,7 @@ export default gql` viewed reacted rating + commented } } } From 3549e575062c387de8c67d62cfaf7bc4d7543761 Mon Sep 17 00:00:00 2001 From: bniwredyc Date: Mon, 3 Apr 2023 14:55:00 +0200 Subject: [PATCH 3/7] scroll to anchor fixes, profile comments link fix --- src/components/Article/CommentsTree.tsx | 4 +- src/components/Article/FullArticle.tsx | 29 +------- src/components/Feed/Card.tsx | 15 +--- src/components/Nav/ProfilePopup.tsx | 19 +---- src/components/Views/Author.tsx | 6 +- src/stores/router.ts | 96 +++++++++++++------------ 6 files changed, 65 insertions(+), 104 deletions(-) diff --git a/src/components/Article/CommentsTree.tsx b/src/components/Article/CommentsTree.tsx index a6ac5449..9d61e3d1 100644 --- a/src/components/Article/CommentsTree.tsx +++ b/src/components/Article/CommentsTree.tsx @@ -108,7 +108,7 @@ export const CommentsTree = (props: Props) => { return ( <>
    -

    +

    {t('Comments')} {comments().length.toString() || ''} 0}>  +{newReactions().length} @@ -161,7 +161,7 @@ export const CommentsTree = (props: Props) => { + - diff --git a/src/components/Nav/ProfilePopup.tsx b/src/components/Nav/ProfilePopup.tsx index 1d5bfd5b..b19ae5ff 100644 --- a/src/components/Nav/ProfilePopup.tsx +++ b/src/components/Nav/ProfilePopup.tsx @@ -2,10 +2,9 @@ import { useSession } from '../../context/session' import type { PopupProps } from '../_shared/Popup' import { Popup } from '../_shared/Popup' import styles from '../_shared/Popup/Popup.module.scss' -import { getPagePath, openPage } from '@nanostores/router' -import { router, useRouter } from '../../stores/router' +import { getPagePath } from '@nanostores/router' +import { router } from '../../stores/router' import { useLocalize } from '../../context/localize' -import type { AuthorPageSearchParams } from '../Views/Author' type ProfilePopupProps = Omit @@ -16,12 +15,6 @@ export const ProfilePopup = (props: ProfilePopupProps) => { } = useSession() const { t } = useLocalize() - const { changeSearchParam } = useRouter() - - const openAuthorComments = () => { - openPage(router, 'author', { slug: userSlug() }) - changeSearchParam('by', 'commented') - } return ( @@ -36,13 +29,7 @@ export const ProfilePopup = (props: ProfilePopupProps) => { {t('Subscriptions')}
  • - { - event.preventDefault() - openAuthorComments() - }} - > + {t('Comments')}
  • diff --git a/src/components/Views/Author.tsx b/src/components/Views/Author.tsx index 535c915a..b4e94de5 100644 --- a/src/components/Views/Author.tsx +++ b/src/components/Views/Author.tsx @@ -54,7 +54,11 @@ export const AuthorView = (props: AuthorProps) => { const { searchParams, changeSearchParam } = useRouter() - changeSearchParam('by', 'rating') + onMount(() => { + if (!searchParams().by) { + changeSearchParam('by', 'rating') + } + }) const loadMore = async () => { saveScrollPosition() diff --git a/src/stores/router.ts b/src/stores/router.ts index ad7afc8d..c21d25b8 100644 --- a/src/stores/router.ts +++ b/src/stores/router.ts @@ -40,9 +40,8 @@ const routerStore = createRouter(ROUTES, { export const router = routerStore -const handleClientRouteLinkClick = (event) => { - const link = event.target.closest('a') - if ( +const checkOpenOnClient = (link: HTMLAnchorElement, event) => { + return ( link && event.button === 0 && link.target !== '_blank' && @@ -52,48 +51,58 @@ const handleClientRouteLinkClick = (event) => { !event.ctrlKey && !event.shiftKey && !event.altKey - ) { - const url = new URL(link.href) - if (url.origin === location.origin) { - event.preventDefault() + ) +} - if (url.pathname) { - routerStore.open(url.pathname) - } +const handleClientRouteLinkClick = (event) => { + const link = event.target.closest('a') - if (url.search) { - const params = Object.fromEntries(new URLSearchParams(url.search)) - searchParamsStore.open(params) - } - - if (url.hash) { - let selector = url.hash - - if (/^#\d+/.test(selector)) { - // id="1" fix - // https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers - selector = `[id="${selector.replace('#', '')}"]` - } - - const anchor = document.querySelector(selector) - const headerOffset = 80 // 100px for header - const elementPosition = anchor ? anchor.getBoundingClientRect().top : 0 - const newScrollTop = elementPosition + window.scrollY - headerOffset - - window.scrollTo({ - top: newScrollTop, - behavior: 'smooth' - }) - - return - } - - window.scrollTo({ - top: 0, - left: 0 - }) - } + if (!checkOpenOnClient(link, event)) { + return } + + const url = new URL(link.href) + if (url.origin !== location.origin) { + return + } + + event.preventDefault() + + if (url.pathname) { + routerStore.open(url.pathname) + } + + if (url.search) { + const params = Object.fromEntries(new URLSearchParams(url.search)) + searchParamsStore.open(params) + } + + if (url.hash) { + let selector = url.hash + + if (/^#\d+/.test(selector)) { + // id="1" fix + // https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers + selector = `[id="${selector.replace('#', '')}"]` + } + + const anchor = document.querySelector(selector) + const headerOffset = 80 // 100px for header + const elementPosition = anchor ? anchor.getBoundingClientRect().top : 0 + const newScrollTop = elementPosition + window.scrollY - headerOffset + + window.scrollTo({ + top: newScrollTop, + behavior: 'smooth' + }) + + return + } + + window.scrollTo({ + top: 0, + left: 0 + }) } export const initRouter = (pathname: string, search: Record) => { @@ -134,7 +143,6 @@ export const useRouter = = Record< return { page, searchParams, - changeSearchParam, - handleClientRouteLinkClick + changeSearchParam } } From 71fb5c52765ff6f7d33ad9e95840cef2ffe421da Mon Sep 17 00:00:00 2001 From: bniwredyc Date: Mon, 3 Apr 2023 15:11:02 +0200 Subject: [PATCH 4/7] build fix --- src/components/Article/FullArticle.tsx | 4 ++-- src/components/Views/Search.tsx | 10 +++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx index d057aa91..4d9a5a6f 100644 --- a/src/components/Article/FullArticle.tsx +++ b/src/components/Article/FullArticle.tsx @@ -185,10 +185,10 @@ export const FullArticle = (props: ArticleProps) => {

    - +
    { const [query, setQuery] = createSignal(props.query) const [offset, setOffset] = createSignal(0) - const { searchParams, handleClientRouteLinkClick } = useRouter() + const { searchParams } = useRouter() let searchEl: HTMLInputElement const handleQueryChange = (_ev) => { setQuery(searchEl.value) @@ -72,18 +72,14 @@ export const SearchView = (props: Props) => { selected: searchParams().by === 'relevance' }} > - - {t('By relevance')} - + {t('By relevance')}
  • - - {t('Top rated')} - + {t('Top rated')}
  • From 4a8c2bea779d28c9e6010e0feb088509a583b3a2 Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Mon, 3 Apr 2023 16:38:44 +0300 Subject: [PATCH 5/7] perfectionism mode --- src/components/Article/CommentsTree.tsx | 3 +-- src/components/Article/FullArticle.tsx | 2 +- src/components/Feed/Card.tsx | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/Article/CommentsTree.tsx b/src/components/Article/CommentsTree.tsx index 9d61e3d1..f809c0a4 100644 --- a/src/components/Article/CommentsTree.tsx +++ b/src/components/Article/CommentsTree.tsx @@ -10,7 +10,6 @@ import { useReactions } from '../../context/reactions' import { byCreated } from '../../utils/sortby' import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated' import { useLocalize } from '../../context/localize' -import Cookie from 'js-cookie' type CommentsOrder = 'createdAt' | 'rating' | 'newOnly' @@ -148,7 +147,7 @@ export const CommentsTree = (props: Props) => {
      - !r.replyTo)}> + !r.replyTo)}> {(reaction) => ( { - {/*{props.article.stat?.commented || ''}*/} + {props.article.stat?.commented ?? ''}
      diff --git a/src/components/Feed/Card.tsx b/src/components/Feed/Card.tsx index 6033fb3d..4424badf 100644 --- a/src/components/Feed/Card.tsx +++ b/src/components/Feed/Card.tsx @@ -155,7 +155,6 @@ export const ArticleCard = (props: ArticleCardProps) => {
      -
      {formattedDate()}
      From dace7daca8a5f98a9729f5baae2aff33c2d9ea16 Mon Sep 17 00:00:00 2001 From: bniwredyc Date: Mon, 3 Apr 2023 16:22:59 +0200 Subject: [PATCH 6/7] wait for page to load befor scroll to anchor --- src/pages/article.page.tsx | 5 ++- src/stores/router.ts | 68 +++++++++++++++++++++++++----------- src/utils/pageLoadManager.ts | 11 ++++++ 3 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 src/utils/pageLoadManager.ts diff --git a/src/pages/article.page.tsx b/src/pages/article.page.tsx index 8378bf37..bece4351 100644 --- a/src/pages/article.page.tsx +++ b/src/pages/article.page.tsx @@ -7,6 +7,7 @@ import { useRouter } from '../stores/router' import { Loading } from '../components/_shared/Loading' import { ReactionsProvider } from '../context/reactions' import { FullArticle } from '../components/Article/FullArticle' +import { setPageLoadManagerPromise } from '../utils/pageLoadManager' export const ArticlePage = (props: PageProps) => { const shouts = props.article ? [props.article] : [] @@ -33,7 +34,9 @@ export const ArticlePage = (props: PageProps) => { const articleValue = articleEntities()[slug()] if (!articleValue || !articleValue.body) { - await loadShout(slug()) + const loadShoutPromise = loadShout(slug()) + setPageLoadManagerPromise(loadShoutPromise) + await loadShoutPromise } }) diff --git a/src/stores/router.ts b/src/stores/router.ts index c21d25b8..a2d7c3c5 100644 --- a/src/stores/router.ts +++ b/src/stores/router.ts @@ -2,6 +2,8 @@ import type { Accessor } from 'solid-js' import { createRouter, createSearchParams } from '@nanostores/router' import { isServer } from 'solid-js/web' import { useStore } from '@nanostores/solid' +import { loadShoutPromise } from './zine/articles' +import { getPageLoadManagerPromise } from '../utils/pageLoadManager' export const ROUTES = { home: '/', @@ -54,7 +56,27 @@ const checkOpenOnClient = (link: HTMLAnchorElement, event) => { ) } -const handleClientRouteLinkClick = (event) => { +const scrollToHash = (hash: string) => { + let selector = hash + + if (/^#\d+/.test(selector)) { + // id="1" fix + // https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers + selector = `[id="${selector.replace('#', '')}"]` + } + + const anchor = document.querySelector(selector) + const headerOffset = 80 // 100px for header + const elementPosition = anchor ? anchor.getBoundingClientRect().top : 0 + const newScrollTop = elementPosition + window.scrollY - headerOffset + + window.scrollTo({ + top: newScrollTop, + behavior: 'smooth' + }) +} + +const handleClientRouteLinkClick = async (event) => { const link = event.target.closest('a') if (!checkOpenOnClient(link, event)) { @@ -77,31 +99,37 @@ const handleClientRouteLinkClick = (event) => { searchParamsStore.open(params) } - if (url.hash) { - let selector = url.hash - - if (/^#\d+/.test(selector)) { - // id="1" fix - // https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers - selector = `[id="${selector.replace('#', '')}"]` - } - - const anchor = document.querySelector(selector) - const headerOffset = 80 // 100px for header - const elementPosition = anchor ? anchor.getBoundingClientRect().top : 0 - const newScrollTop = elementPosition + window.scrollY - headerOffset - + if (!url.hash) { window.scrollTo({ - top: newScrollTop, - behavior: 'smooth' + top: 0, + left: 0 }) return } - window.scrollTo({ - top: 0, - left: 0 + await getPageLoadManagerPromise() + + const images = document.querySelectorAll('img') + + let imagesLoaded = 0 + + const imageLoadEventHandler = () => { + imagesLoaded++ + if (imagesLoaded === images.length) { + scrollToHash(url.hash) + images.forEach((image) => image.removeEventListener('load', imageLoadEventHandler)) + images.forEach((image) => image.removeEventListener('error', imageLoadEventHandler)) + } + } + + images.forEach((image) => { + if (image.complete) { + imagesLoaded++ + } + + image.addEventListener('load', imageLoadEventHandler) + image.addEventListener('error', imageLoadEventHandler) }) } diff --git a/src/utils/pageLoadManager.ts b/src/utils/pageLoadManager.ts new file mode 100644 index 00000000..d04a3d3d --- /dev/null +++ b/src/utils/pageLoadManager.ts @@ -0,0 +1,11 @@ +const pageLoadManager: { + promise: Promise +} = { promise: Promise.resolve() } + +export const getPageLoadManagerPromise = () => { + return pageLoadManager.promise +} + +export const setPageLoadManagerPromise = (promise: Promise) => { + pageLoadManager.promise = promise +} From 0d8c3820158366cdaf8500da8fc9e9cdc3826285 Mon Sep 17 00:00:00 2001 From: bniwredyc Date: Mon, 3 Apr 2023 16:31:12 +0200 Subject: [PATCH 7/7] build fix --- src/components/Article/CommentsTree.tsx | 2 +- src/stores/router.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Article/CommentsTree.tsx b/src/components/Article/CommentsTree.tsx index f809c0a4..5e4a9c88 100644 --- a/src/components/Article/CommentsTree.tsx +++ b/src/components/Article/CommentsTree.tsx @@ -147,7 +147,7 @@ export const CommentsTree = (props: Props) => {
      - !r.replyTo)}> + !r.replyTo)}> {(reaction) => (