diff --git a/src/components/LibraryLayout.tsx b/src/components/LibraryLayout.tsx index 71c2790fa..6cf10e3df 100644 --- a/src/components/LibraryLayout.tsx +++ b/src/components/LibraryLayout.tsx @@ -4,6 +4,7 @@ import { GithubIcon } from '~/components/icons/GithubIcon' import { DiscordIcon } from '~/components/icons/DiscordIcon' import { Link, useMatches, useParams } from '@tanstack/react-router' import { useLocalStorage } from '~/utils/useLocalStorage' +import { useMediaQuery } from '~/utils/useMediaQuery' import { useClickOutside } from '~/hooks/useClickOutside' import { last } from '~/utils/utils' import type { ConfigSchema, MenuItem } from '~/utils/config' @@ -424,26 +425,6 @@ function clampProgress(value: number) { return Math.min(Math.max(value, 0), 1) } -function useMediaQuery(query: string) { - const [matches, setMatches] = React.useState(false) - - React.useEffect(() => { - const mediaQueryList = window.matchMedia(query) - const updateMatches = () => { - setMatches(mediaQueryList.matches) - } - - updateMatches() - mediaQueryList.addEventListener('change', updateMatches) - - return () => { - mediaQueryList.removeEventListener('change', updateMatches) - } - }, [query]) - - return matches -} - function areDocsPartnerSlotsEqual( left: DocsPartnerScrollSlot | undefined, right: DocsPartnerScrollSlot | undefined, @@ -903,6 +884,7 @@ export function LibraryLayout({ surface: 'docs_rail', }) const shouldShowDocsPartnerSlot = useMediaQuery('(max-width: 767.98px)') + const isDesktopViewport = useMediaQuery('(min-width: 768px)') const groupInitialOpenState = React.useMemo(() => { return visibleMenuConfig.reduce>( @@ -1431,7 +1413,7 @@ export function LibraryLayout({ partners={activePartners} />
- +
)} diff --git a/src/components/RecentPostsWidget.tsx b/src/components/RecentPostsWidget.tsx index 858df3b7a..3dad2208c 100644 --- a/src/components/RecentPostsWidget.tsx +++ b/src/components/RecentPostsWidget.tsx @@ -5,6 +5,8 @@ import { formatPublishedDate } from '~/utils/blog' type RecentPostsWidgetProps = { posts?: ReadonlyArray + /** Set to false to skip the client fetch when the widget is rendered but not visible (e.g. hidden below a CSS breakpoint). Ignored when `posts` is provided. */ + enabled?: boolean } function RecentPostsList({ posts }: { posts: ReadonlyArray }) { @@ -63,11 +65,14 @@ function RecentPostsSkeleton() { ) } -export function RecentPostsWidget({ posts }: RecentPostsWidgetProps) { +export function RecentPostsWidget({ + posts, + enabled = true, +}: RecentPostsWidgetProps) { const recentPostsQuery = useQuery({ queryKey: ['recentPosts'], queryFn: () => fetchRecentPosts(), - enabled: posts === undefined, + enabled: posts === undefined && enabled, staleTime: 1000 * 60 * 5, }) diff --git a/src/routes/blog.$.tsx b/src/routes/blog.$.tsx index 48232a5d8..dc41a6b1e 100644 --- a/src/routes/blog.$.tsx +++ b/src/routes/blog.$.tsx @@ -9,6 +9,7 @@ import { LibrariesWidget } from '~/components/LibrariesWidget' import { partners } from '~/utils/partners' import { PartnersRail, RightRail } from '~/components/RightRail' import { RecentPostsWidget } from '~/components/RecentPostsWidget' +import { useMediaQuery } from '~/utils/useMediaQuery' import { Toc } from '~/components/Toc' import { Breadcrumbs } from '~/components/Breadcrumbs' @@ -76,6 +77,7 @@ function BlogPost() { const headings = markdown.headings const isTocVisible = headings.length > 1 + const isDesktopViewport = useMediaQuery('(min-width: 768px)') const markdownContainerRef = React.useRef(null) const [activeHeadings, setActiveHeadings] = React.useState>([]) @@ -203,7 +205,7 @@ function BlogPost() { partners={activePartners} />
- +
diff --git a/src/utils/useMediaQuery.ts b/src/utils/useMediaQuery.ts new file mode 100644 index 000000000..2112184d0 --- /dev/null +++ b/src/utils/useMediaQuery.ts @@ -0,0 +1,21 @@ +import * as React from 'react' + +export function useMediaQuery(query: string) { + const [matches, setMatches] = React.useState(false) + + React.useEffect(() => { + const mediaQueryList = window.matchMedia(query) + const updateMatches = () => { + setMatches(mediaQueryList.matches) + } + + updateMatches() + mediaQueryList.addEventListener('change', updateMatches) + + return () => { + mediaQueryList.removeEventListener('change', updateMatches) + } + }, [query]) + + return matches +}