diff --git a/src/components/Article/CommentsTree.tsx b/src/components/Article/CommentsTree.tsx index f5e6e1be..2ef2cf52 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' @@ -110,7 +109,7 @@ export const CommentsTree = (props: Props) => { return ( <>
+
{t('Comments')} {comments().length.toString() || ''} 0}>
+{newReactions().length}
@@ -166,7 +165,7 @@ export const CommentsTree = (props: Props) => {
+
{t('To write a comment, you must')}{' '}
{t('sign up')}
diff --git a/src/components/Article/FullArticle.tsx b/src/components/Article/FullArticle.tsx
index b1fe6a7d..6600c160 100644
--- a/src/components/Article/FullArticle.tsx
+++ b/src/components/Article/FullArticle.tsx
@@ -1,7 +1,7 @@
import { capitalize, formatDate } from '../../utils'
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'
@@ -13,7 +13,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'
@@ -65,19 +65,6 @@ export const FullArticle = (props: ArticleProps) => {
props.article.topics[0]
)
- onMount(() => {
- const windowHash = window.location.hash
- if (windowHash?.length > 0) {
- const comments = document.querySelector(windowHash)
- if (comments) {
- window.scrollTo({
- top: comments.getBoundingClientRect().top,
- behavior: 'smooth'
- })
- }
- }
- })
-
onMount(async () => {
await loadReactionsBy({
by: { shout: props.article.slug }
@@ -104,14 +91,6 @@ export const FullArticle = (props: ArticleProps) => {
actions: { loadReactionsBy }
} = useReactions()
- let commentsRef: HTMLDivElement | undefined
- const scrollToComments = () => {
- if (!isReactionsLoaded()) {
- return
- }
- commentsRef.scrollIntoView({ behavior: 'smooth' })
- }
-
return (
<>
{props.article.title}
@@ -205,12 +184,10 @@ export const FullArticle = (props: ArticleProps) => {
- scrollToComments()}>
-
-
- {/*{props.article.stat?.commented || ''}*/}
-
-
+
+
+ {props.article.stat?.commented ?? ''}
+
{
)}
-
+
{
-
{formattedDate()}
@@ -173,7 +172,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
-
+
{stat?.commented || t('Add comment')}
diff --git a/src/components/Nav/ProfilePopup.tsx b/src/components/Nav/ProfilePopup.tsx
index ea154d8b..7eed9739 100644
--- a/src/components/Nav/ProfilePopup.tsx
+++ b/src/components/Nav/ProfilePopup.tsx
@@ -29,7 +29,9 @@ export const ProfilePopup = (props: ProfilePopupProps) => {
{t('Subscriptions')}
- {t('Comments')}
+
+ {t('Comments')}
+
{t('Bookmarks')}
diff --git a/src/components/Views/Author.tsx b/src/components/Views/Author.tsx
index e24f7139..15d2511e 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'
}
@@ -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()
@@ -131,7 +135,7 @@ export const AuthorView = (props: AuthorProps) => {
*/}
diff --git a/src/components/Views/Search.tsx b/src/components/Views/Search.tsx
index e2717b6a..215c1e13 100644
--- a/src/components/Views/Search.tsx
+++ b/src/components/Views/Search.tsx
@@ -26,7 +26,7 @@ export const SearchView = (props: Props) => {
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')}
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
}
}
}
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 2904b23a..94e8789f 100644
--- a/src/stores/router.ts
+++ b/src/stores/router.ts
@@ -2,6 +2,7 @@ import type { Accessor } from 'solid-js'
import { createRouter, createSearchParams } from '@nanostores/router'
import { isServer } from 'solid-js/web'
import { useStore } from '@nanostores/solid'
+import { getPageLoadManagerPromise } from '../utils/pageLoadManager'
export const ROUTES = {
home: '/',
@@ -40,9 +41,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,43 +52,84 @@ const handleClientRouteLinkClick = (event) => {
!event.ctrlKey &&
!event.shiftKey &&
!event.altKey
- ) {
- const url = new URL(link.href)
- if (url.origin === location.origin) {
- event.preventDefault()
+ )
+}
- if (url.hash) {
- let selector = url.hash
+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('#', '')}"]`
- }
+ 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 // 80px for header
- const elementPosition = anchor ? anchor.getBoundingClientRect().top : 0
- const newScrollTop = elementPosition + window.scrollY - headerOffset
+ const anchor = document.querySelector(selector)
+ const headerOffset = 80 // 80px for header
+ const elementPosition = anchor ? anchor.getBoundingClientRect().top : 0
+ const newScrollTop = elementPosition + window.scrollY - headerOffset
- window.scrollTo({
- top: newScrollTop,
- behavior: 'smooth'
- })
+ window.scrollTo({
+ top: newScrollTop,
+ behavior: 'smooth'
+ })
+}
- return
- }
+const handleClientRouteLinkClick = async (event) => {
+ const link = event.target.closest('a')
- routerStore.open(url.pathname)
- const params = Object.fromEntries(new URLSearchParams(url.search))
- searchParamsStore.open(params)
+ if (!checkOpenOnClient(link, event)) {
+ return
+ }
- window.scrollTo({
- top: 0,
- left: 0
- })
+ 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) {
+ window.scrollTo({
+ top: 0,
+ left: 0
+ })
+
+ return
+ }
+
+ 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)
+ })
}
export const initRouter = (pathname: string, search: Record) => {
@@ -129,7 +170,6 @@ export const useRouter = = Record<
return {
page,
searchParams,
- changeSearchParam,
- handleClientRouteLinkClick
+ changeSearchParam
}
}
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
+}