Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/components/LazyMarkdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Suspense, lazy } from 'react'
import { useIntersectionObserver } from '~/hooks/useIntersectionObserver'

const Markdown = lazy(() =>
import('./Markdown').then((mod) => ({ default: mod.Markdown })),
)

interface LazyMarkdownProps {
rawContent: string
className?: string
}

export function LazyMarkdown({ rawContent, className }: LazyMarkdownProps) {
const { ref, isIntersecting } = useIntersectionObserver({
rootMargin: '100px',
triggerOnce: true,
})

return (
<div ref={ref} className={className}>
{isIntersecting ? (
<Suspense fallback={null}>
<Markdown rawContent={rawContent} />
</Suspense>
) : null}
</div>
)
}
24 changes: 18 additions & 6 deletions src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const Route = createRootRouteWithContext<{
}),
],
links: [
{ rel: 'preload', href: appCss, as: 'style' },
{ rel: 'stylesheet', href: appCss },
{
rel: 'apple-touch-icon',
Expand Down Expand Up @@ -91,14 +92,25 @@ export const Route = createRootRouteWithContext<{
},
],
scripts: [
// Google Tag Manager script
// Google Tag Manager - deferred until user interaction or timeout
{
children: `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-5N57KQT4');
(function(){
var loaded=false;
function loadGTM(){
if(loaded)return;
loaded=true;
var w=window,d=document,l='dataLayer',i='GTM-5N57KQT4';
w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});
var f=d.getElementsByTagName('script')[0],j=d.createElement('script');
j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i;
f.parentNode.insertBefore(j,f);
}
['scroll','click','touchstart','keydown'].forEach(function(e){
window.addEventListener(e,loadGTM,{once:true,passive:true});
});
setTimeout(loadGTM,4000);
})();
`,
},
],
Expand Down
166 changes: 94 additions & 72 deletions src/routes/_libraries/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { Link, MatchRoute, createFileRoute } from '@tanstack/react-router'
import {
Await,
Link,
MatchRoute,
createFileRoute,
} from '@tanstack/react-router'
import { twMerge } from 'tailwind-merge'
import { Footer } from '~/components/Footer'
import { LazySponsorSection } from '~/components/LazySponsorSection'
Expand All @@ -17,7 +22,7 @@ import { coreMaintainers } from '~/libraries/maintainers'
import { useToast } from '~/components/ToastProvider'
import { formatAuthors, getPublishedPosts } from '~/utils/blog'
import { format } from 'date-fns'
import { Markdown } from '~/components/Markdown'
import { LazyMarkdown } from '~/components/LazyMarkdown'
import { createServerFn } from '@tanstack/react-start'
import { setResponseHeaders } from '@tanstack/react-start/server'
import { AdGate } from '~/contexts/AdsContext'
Expand Down Expand Up @@ -70,11 +75,11 @@ const fetchRecentPosts = createServerFn({ method: 'GET' }).handler(async () => {

export const Route = createFileRoute('/_libraries/')({
loader: async ({ context: { queryClient } }) => {
await queryClient.ensureQueryData(ossStatsQuery())
const recentPosts = await fetchRecentPosts()
queryClient.ensureQueryData(ossStatsQuery())
const recentPostsPromise = fetchRecentPosts()

return {
recentPosts,
recentPostsPromise,
}
},
component: Index,
Expand All @@ -101,7 +106,7 @@ function Index() {
fn: bytesSignupServerFn,
})
const { notify } = useToast()
const { recentPosts } = Route.useLoaderData()
const { recentPostsPromise } = Route.useLoaderData()

// sponsorsPromise no longer needed - using lazy loading

Expand All @@ -115,11 +120,13 @@ function Index() {
src={'/images/logos/splash-light.png'}
className="w-[300px] pt-8 xl:pt-0 xl:w-[400px] 2xl:w-[500px] dark:hidden"
alt="TanStack Logo"
fetchPriority="high"
/>
<img
src={'/images/logos/splash-dark.png'}
className="w-[300px] pt-8 xl:pt-0 xl:w-[400px] 2xl:w-[500px] hidden dark:block"
alt="TanStack Logo"
fetchPriority="high"
/>
</BrandContextMenu>
<div className="flex flex-col items-center gap-6 text-center px-4 xl:text-left xl:items-start">
Expand Down Expand Up @@ -372,80 +379,95 @@ function Index() {
</div>
</div>

{recentPosts && recentPosts.length > 0 && (
<div className="px-4 lg:max-w-(--breakpoint-lg) md:mx-auto">
<h3 id="blog" className={`text-4xl font-light mb-6 scroll-mt-24`}>
<a
href="#blog"
className="hover:underline decoration-gray-400 dark:decoration-gray-600"
>
Latest Blog Posts
</a>
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{recentPosts.map(
({ slug, title, published, excerpt, authors }) => {
return (
<Link
key={slug}
to="/blog/$"
params={{ _splat: slug }}
className={`flex flex-col gap-3 justify-between
<Await promise={recentPostsPromise}>
{(recentPosts: any) => (
<>
{recentPosts && recentPosts.length > 0 && (
<div className="px-4 lg:max-w-(--breakpoint-lg) md:mx-auto">
<h3
id="blog"
className={`text-4xl font-light mb-6 scroll-mt-24`}
>
<a
href="#blog"
className="hover:underline decoration-gray-400 dark:decoration-gray-600"
>
Latest Blog Posts
</a>
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{recentPosts.map(
({ slug, title, published, excerpt, authors }) => {
return (
<Link
key={slug}
to="/blog/$"
params={{ _splat: slug }}
className={`flex flex-col gap-3 justify-between
border-2 border-transparent rounded-lg p-4
transition-all bg-white/90 dark:bg-black/40
shadow-md dark:shadow-lg dark:shadow-blue-500/20
hover:border-blue-500 hover:shadow-xl
`}
>
<div>
<div className={`text-base font-bold`}>{title}</div>
<div
className={`text-xs italic font-light mt-1 text-gray-600 dark:text-gray-400`}
>
<p>
by {formatAuthors(authors)}
{published ? (
<time
dateTime={published}
title={format(
new Date(published),
'MMM dd, yyyy',
)}
>
{' '}
on {format(new Date(published), 'MMM dd, yyyy')}
</time>
) : null}
</p>
</div>
{excerpt && (
<div
className={`text-xs mt-3 text-gray-700 dark:text-gray-300 line-clamp-2 leading-relaxed`}
>
<Markdown rawContent={excerpt} />
</div>
)}
</div>
<div>
<div className="text-blue-500 uppercase font-bold text-xs">
Read More →
</div>
</div>
<div>
<div className={`text-base font-bold`}>
{title}
</div>
<div
className={`text-xs italic font-light mt-1 text-gray-600 dark:text-gray-400`}
>
<p>
by {formatAuthors(authors)}
{published ? (
<time
dateTime={published}
title={format(
new Date(published),
'MMM dd, yyyy',
)}
>
{' '}
on{' '}
{format(
new Date(published),
'MMM dd, yyyy',
)}
</time>
) : null}
</p>
</div>
{excerpt && (
<div
className={`text-xs mt-3 text-gray-700 dark:text-gray-300 line-clamp-2 leading-relaxed`}
>
<LazyMarkdown rawContent={excerpt} />
</div>
)}
</div>
<div>
<div className="text-blue-500 uppercase font-bold text-xs">
Read More →
</div>
</div>
</Link>
)
},
)}
</div>
<div className="text-center mt-6">
<Link
to="/blog"
className="inline-flex items-center text-sm text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 transition-colors"
>
View All Posts →
</Link>
)
},
</div>
</div>
)}
</div>
<div className="text-center mt-6">
<Link
to="/blog"
className="inline-flex items-center text-sm text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 transition-colors"
>
View All Posts →
</Link>
</div>
</div>
)}
</>
)}
</Await>

<div className={`lg:max-w-(--breakpoint-lg) px-4 mx-auto`}>
<h3 id="courses" className={`text-4xl font-light mb-6 scroll-mt-24`}>
Expand Down
Loading