Show og image grid for tags
This commit is contained in:
parent
4c725dd481
commit
235d4b0b5f
@ -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,
|
||||
},
|
||||
);
|
||||
|
||||
30
src/app/(static)/t/[tag]/image/route.tsx
Normal file
30
src/app/(static)/t/[tag]/image/route.tsx
Normal 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,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -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} />
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
11
src/tag/index.ts
Normal 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'}`;
|
||||
@ -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(' ');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user