Show og image grid for tags

This commit is contained in:
Sam Becker 2023-09-14 17:25:18 -05:00
parent 4c725dd481
commit 235d4b0b5f
7 changed files with 89 additions and 21 deletions

View File

@ -3,14 +3,12 @@ import { getImageCacheHeadersForAuth } from '@/cache';
import HomeImageResponse from '@/photo/image-response/HomeImageResponse';
import { getPhotos } from '@/services/postgres';
import { IMAGE_OG_SMALL_HEIGHT, IMAGE_OG_SMALL_WIDTH } from '@/site';
import { FONT_FAMILY_IBM_PLEX_MONO, getIBMPlexMonoMedium } from '@/site/font';
import { ImageResponse } from '@vercel/og';
export const runtime = 'edge';
export async function GET(request: Request) {
const photos = await getPhotos();
const fontData = await getIBMPlexMonoMedium();
const headers = await getImageCacheHeadersForAuth(await auth());
return new ImageResponse(
@ -18,23 +16,13 @@ export async function GET(request: Request) {
<HomeImageResponse {...{
photos,
request,
includeHeader: false,
outerMargin: 0,
width: IMAGE_OG_SMALL_WIDTH,
height: IMAGE_OG_SMALL_HEIGHT,
fontFamily: FONT_FAMILY_IBM_PLEX_MONO,
}}/>
),
{
width: IMAGE_OG_SMALL_WIDTH,
height: IMAGE_OG_SMALL_HEIGHT,
fonts: [
{
name: FONT_FAMILY_IBM_PLEX_MONO,
data: fontData,
style: 'normal',
},
],
headers,
},
);

View File

@ -0,0 +1,30 @@
import { auth } from '@/auth';
import { getImageCacheHeadersForAuth } from '@/cache';
import HomeImageResponse from '@/photo/image-response/HomeImageResponse';
import { getPhotos } from '@/services/postgres';
import { IMAGE_OG_SMALL_HEIGHT, IMAGE_OG_SMALL_WIDTH } from '@/site';
import { ImageResponse } from '@vercel/og';
export const runtime = 'edge';
export async function GET(request: Request, context: any) {
const photos = await getPhotos(
undefined, undefined, undefined, context.params.tag);
const headers = await getImageCacheHeadersForAuth(await auth());
return new ImageResponse(
(
<HomeImageResponse {...{
photos,
request,
width: IMAGE_OG_SMALL_WIDTH,
height: IMAGE_OG_SMALL_HEIGHT,
}}/>
),
{
width: IMAGE_OG_SMALL_WIDTH,
height: IMAGE_OG_SMALL_HEIGHT,
headers,
},
);
}

View File

@ -1,13 +1,38 @@
import SiteGrid from '@/components/SiteGrid';
import PhotoGrid from '@/photo/PhotoGrid';
import { getPhotos } from '@/services/postgres';
import { absolutePathForTagImage } from '@/site/paths';
import {
descriptionForTaggedPhotos,
ogTitleForTag,
pageTitleForTag,
} from '@/tag';
import PhotoTag from '@/tag/PhotoTag';
import { Metadata } from 'next';
export default async function TagPage({
params: { tag },
}: {
interface TagProps {
params: { tag: string }
}) {
}
export async function generateMetadata({
params: { tag },
}: TagProps): Promise<Metadata> {
const photos = await getPhotos(undefined, undefined, undefined, tag);
return {
title: pageTitleForTag(tag),
openGraph: {
title: ogTitleForTag(tag),
images: absolutePathForTagImage(tag),
},
twitter: {
card: 'summary_large_image',
images: absolutePathForTagImage(tag),
},
description: descriptionForTaggedPhotos(photos),
};
}
export default async function TagPage({ params: { tag } }: TagProps) {
const photos = await getPhotos(undefined, undefined, undefined, tag);
return (
@ -16,7 +41,7 @@ export default async function TagPage({
<div className="flex items-center gap-2">
<PhotoTag tag={tag} />
<span className="uppercase text-gray-400 dark:text-gray-500">
{photos.length} {photos.length === 1 ? 'photo' : 'photos'}
{descriptionForTaggedPhotos(photos)}
</span>
</div>
<PhotoGrid photos={photos} />

View File

@ -6,18 +6,18 @@ export default function HomeImageResponse({
request,
width,
height,
fontFamily,
}: {
photos: Photo[]
request: Request
width: number
height: number
fontFamily: string
}) {
const grid = photos.length >= 12
? { colCount: 4, rowCount: 3 }
: { colCount: 3, rowCount: 2 };
const photosPerGrid = grid.colCount * grid.rowCount;
return (
<div style={{
display: 'flex',
@ -27,10 +27,9 @@ export default function HomeImageResponse({
background: 'transparent',
width,
height,
fontFamily,
}}>
<PhotoGridImageResponse {...{
photos,
photos: photos.slice(0, photosPerGrid),
request,
nextImageWidth: 200,
...grid,

View File

@ -24,9 +24,15 @@ export const pathForTag = (tag: string) => `${PREFIX_TAG}/${tag}`;
export const absolutePathForPhoto = (photo: Photo) =>
`${BASE_URL}${pathForPhoto(photo)}`;
export const absolutePathForTag = (tag: string) =>
`${BASE_URL}${pathForTag(tag)}`;
export const absolutePathForPhotoImage = (photo: Photo) =>
`${absolutePathForPhoto(photo)}/image`;
export const absolutePathForTagImage = (tag: string) =>
`${absolutePathForTag(tag)}/image`;
export const isPathPhoto = (pathname = '') =>
/^\/p\/[^/]+\/?$/.test(pathname);

11
src/tag/index.ts Normal file
View File

@ -0,0 +1,11 @@
import { Photo } from '@/photo';
import { capitalizeWords } from '@/utility/string';
export const pageTitleForTag = (tag: string) =>
`${capitalizeWords(tag.replaceAll('-', ' '))} Photos`;
export const ogTitleForTag = (tag: string) =>
`🏷️ ${tag.toUpperCase()}`;
export const descriptionForTaggedPhotos = (photos:Photo[]) =>
`${photos.length} ${photos.length === 1 ? 'photo' : 'photos'}`;

View File

@ -9,3 +9,12 @@ export const convertStringToArray = (
? tag.trim().replaceAll(' ', '-').toLowerCase()
: tag.trim())
: undefined;
export const capitalize = (string: string) =>
string.charAt(0).toUpperCase() + string.slice(1);
export const capitalizeWords = (string: string) =>
string
.split(' ')
.map(capitalize)
.join(' ');