Test new server action component loader
This commit is contained in:
parent
b20717e8b8
commit
88429b97f4
@ -12,7 +12,7 @@ import {
|
||||
pathForAdminPhotoEdit,
|
||||
} from '@/site/paths';
|
||||
import { titleForPhoto } from '@/photo';
|
||||
import MorePhotos from '@/photo/MorePhotos';
|
||||
import MoreComponentsClient from '@/components/MoreComponentsClient';
|
||||
import {
|
||||
getBlobPhotoUrlsNoStore,
|
||||
getPhotosCached,
|
||||
@ -144,7 +144,10 @@ export default async function AdminPhotosPage({
|
||||
</Fragment>)}
|
||||
</AdminGrid>
|
||||
{showMorePhotos &&
|
||||
<MorePhotos path={pathForAdminPhotos(offset + 1)} />}
|
||||
<MoreComponentsClient
|
||||
label="More photos"
|
||||
path={pathForAdminPhotos(offset + 1)}
|
||||
/>}
|
||||
</div>
|
||||
</div>}
|
||||
/>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { getPhotosCached, getPhotosCountCached } from '@/cache';
|
||||
import MorePhotos from '@/photo/MorePhotos';
|
||||
import MoreComponentsClient from '@/components/MoreComponentsClient';
|
||||
import StaggeredOgPhotos from '@/photo/StaggeredOgPhotos';
|
||||
import {
|
||||
PaginationParams,
|
||||
@ -26,7 +26,10 @@ export default async function GridPage({ searchParams }: PaginationParams) {
|
||||
<StaggeredOgPhotos photos={photos} />
|
||||
</div>
|
||||
{showMorePhotos &&
|
||||
<MorePhotos path={pathForOg(offset + 1)} />}
|
||||
<MoreComponentsClient
|
||||
label="More photos"
|
||||
path={pathForOg(offset + 1)}
|
||||
/>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,19 +1,10 @@
|
||||
import { getPhotosCached, getPhotosCountCached } from '@/cache';
|
||||
import AnimateItems from '@/components/AnimateItems';
|
||||
import MorePhotos from '@/photo/MorePhotos';
|
||||
import SiteGrid from '@/components/SiteGrid';
|
||||
import { getPhotosCached } from '@/cache';
|
||||
import { generateOgImageMetaForPhotos } from '@/photo';
|
||||
import PhotoLarge from '@/photo/PhotoLarge';
|
||||
import PhotosEmptyState from '@/photo/PhotosEmptyState';
|
||||
import {
|
||||
PaginationParams,
|
||||
getPaginationForSearchParams,
|
||||
} from '@/site/pagination';
|
||||
import { pathForRoot } from '@/site/paths';
|
||||
import { Metadata } from 'next';
|
||||
import { MAX_PHOTOS_TO_SHOW_OG } from '@/photo/image-response';
|
||||
|
||||
export const dynamic = 'force-static';
|
||||
import MoreComponents from '@/components/MoreComponents';
|
||||
import PhotosLarge from '@/photo/PhotosLarge';
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
// Make homepage queries resilient to error on first time setup
|
||||
@ -22,40 +13,24 @@ export async function generateMetadata(): Promise<Metadata> {
|
||||
return generateOgImageMetaForPhotos(photos);
|
||||
}
|
||||
|
||||
export default async function HomePage({ searchParams }: PaginationParams) {
|
||||
const { offset, limit } = getPaginationForSearchParams(searchParams, 12);
|
||||
|
||||
const [
|
||||
photos,
|
||||
count,
|
||||
] = await Promise.all([
|
||||
// Make homepage queries resilient to error on first time setup
|
||||
getPhotosCached({ limit }).catch(() => []),
|
||||
getPhotosCountCached().catch(() => 0),
|
||||
]);
|
||||
|
||||
const showMorePhotos = count > photos.length;
|
||||
export default async function HomePage() {
|
||||
// Make homepage queries resilient to error on first time setup
|
||||
const photos = await getPhotosCached({ limit: MAX_PHOTOS_TO_SHOW_OG })
|
||||
.catch(() => []);
|
||||
|
||||
return (
|
||||
photos.length > 0
|
||||
? <div className="space-y-4">
|
||||
<AnimateItems
|
||||
className="space-y-1"
|
||||
duration={0.7}
|
||||
staggerDelay={0.15}
|
||||
distanceOffset={0}
|
||||
staggerOnFirstLoadOnly
|
||||
items={photos.map((photo, index) =>
|
||||
<PhotoLarge
|
||||
key={photo.id}
|
||||
photo={photo}
|
||||
priority={index <= 1}
|
||||
/>)}
|
||||
? <div className="space-y-1">
|
||||
<PhotosLarge photos={photos} />
|
||||
<MoreComponents
|
||||
itemsPerRequest={MAX_PHOTOS_TO_SHOW_OG}
|
||||
componentLoader={async (limit: number) => {
|
||||
'use server';
|
||||
return <PhotosLarge
|
||||
photos={await getPhotosCached({ limit })}
|
||||
/>;
|
||||
}}
|
||||
/>
|
||||
{showMorePhotos &&
|
||||
<SiteGrid
|
||||
contentMain={<MorePhotos path={pathForRoot(offset + 1)} />}
|
||||
/>}
|
||||
</div>
|
||||
: <PhotosEmptyState />
|
||||
);
|
||||
|
||||
27
src/components/MoreComponents.tsx
Normal file
27
src/components/MoreComponents.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export default function MoreComponents({
|
||||
initialOffset = 1,
|
||||
itemsPerRequest,
|
||||
componentLoader,
|
||||
}: {
|
||||
initialOffset?: number
|
||||
itemsPerRequest: number
|
||||
componentLoader: (limit: number) => Promise<JSX.Element>
|
||||
}) {
|
||||
const [offset] = useState(initialOffset);
|
||||
const [components, setComponents] = useState<JSX.Element[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const getPhotosLargeComponentAsync = async () => {
|
||||
return componentLoader(itemsPerRequest * offset);
|
||||
};
|
||||
getPhotosLargeComponentAsync().then((component) => {
|
||||
setComponents([component]);
|
||||
});
|
||||
}, [componentLoader, itemsPerRequest, offset]);
|
||||
|
||||
return components;
|
||||
}
|
||||
@ -2,14 +2,16 @@
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useCallback, useEffect, useRef, useTransition } from 'react';
|
||||
import Spinner from '../components/Spinner';
|
||||
import Spinner from './Spinner';
|
||||
|
||||
export default function MorePhotos({
|
||||
export default function MoreComponentsClient({
|
||||
path,
|
||||
label = 'Load more',
|
||||
triggerOnView = true,
|
||||
prefetch = true,
|
||||
}: {
|
||||
path: string
|
||||
label?: string
|
||||
triggerOnView?: boolean
|
||||
prefetch?: boolean
|
||||
}) {
|
||||
@ -59,7 +61,7 @@ export default function MorePhotos({
|
||||
? <span className="relative inline-block translate-y-[3px]">
|
||||
<Spinner size={16} />
|
||||
</span>
|
||||
: 'More photos'}
|
||||
: label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@ -3,7 +3,7 @@ import PhotoSmall from './PhotoSmall';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import AnimateItems from '@/components/AnimateItems';
|
||||
import { Camera } from '@/camera';
|
||||
import MorePhotos from '@/photo/MorePhotos';
|
||||
import MoreComponentsClient from '@/components/MoreComponentsClient';
|
||||
import { FilmSimulation } from '@/simulation';
|
||||
import { GRID_ASPECT_RATIO, HIGH_DENSITY_GRID } from '@/site/config';
|
||||
|
||||
@ -79,7 +79,10 @@ export default function PhotoGrid({
|
||||
</div>).concat(additionalTile ?? [])}
|
||||
/>
|
||||
{showMorePath &&
|
||||
<MorePhotos path={showMorePath} />}
|
||||
<MoreComponentsClient
|
||||
label="More photos"
|
||||
path={showMorePath}
|
||||
/>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
25
src/photo/PhotosLarge.tsx
Normal file
25
src/photo/PhotosLarge.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import AnimateItems from '@/components/AnimateItems';
|
||||
import { Photo } from '.';
|
||||
import PhotoLarge from './PhotoLarge';
|
||||
|
||||
export default function PhotosLarge({
|
||||
photos,
|
||||
}: {
|
||||
photos: Photo[]
|
||||
}) {
|
||||
return (
|
||||
<AnimateItems
|
||||
className="space-y-1"
|
||||
duration={0.7}
|
||||
staggerDelay={0.15}
|
||||
distanceOffset={0}
|
||||
staggerOnFirstLoadOnly
|
||||
items={photos.map((photo, index) =>
|
||||
<PhotoLarge
|
||||
key={photo.id}
|
||||
photo={photo}
|
||||
priority={index <= 1}
|
||||
/>)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user