feat: refactor og image generation (#639)
@ -3,17 +3,17 @@ import { NextResponse } from 'next/server';
|
||||
|
||||
import { P, match } from 'ts-pattern';
|
||||
|
||||
import { getRecipientOrSenderByShareLinkSlug } from '@documenso/lib/server-only/share/get-recipient-or-sender-by-share-link-slug';
|
||||
|
||||
import { Logo } from '~/components/branding/logo';
|
||||
import { getAssetBuffer } from '~/helpers/get-asset-buffer';
|
||||
import { ShareHandlerAPIResponse } from '~/pages/api/share';
|
||||
|
||||
export const runtime = 'edge';
|
||||
|
||||
const CARD_OFFSET_TOP = 152;
|
||||
const CARD_OFFSET_LEFT = 350;
|
||||
const CARD_WIDTH = 500;
|
||||
const CARD_HEIGHT = 250;
|
||||
|
||||
const size = {
|
||||
const IMAGE_SIZE = {
|
||||
width: 1200,
|
||||
height: 630,
|
||||
};
|
||||
@ -24,15 +24,27 @@ type SharePageOpenGraphImageProps = {
|
||||
|
||||
export async function GET(_request: Request, { params: { slug } }: SharePageOpenGraphImageProps) {
|
||||
const [interSemiBold, interRegular, caveatRegular, shareFrameImage] = await Promise.all([
|
||||
getAssetBuffer('/fonts/inter-semibold.ttf'),
|
||||
getAssetBuffer('/fonts/inter-regular.ttf'),
|
||||
getAssetBuffer('/fonts/caveat-regular.ttf'),
|
||||
getAssetBuffer('/static/og-share-frame.png'),
|
||||
fetch(new URL('@documenso/assets/fonts/inter-semibold.ttf', import.meta.url)).then(
|
||||
async (res) => res.arrayBuffer(),
|
||||
),
|
||||
fetch(new URL('@documenso/assets/fonts/inter-regular.ttf', import.meta.url)).then(async (res) =>
|
||||
res.arrayBuffer(),
|
||||
),
|
||||
fetch(new URL('@documenso/assets/fonts/caveat-regular.ttf', import.meta.url)).then(
|
||||
async (res) => res.arrayBuffer(),
|
||||
),
|
||||
fetch(new URL('@documenso/assets/static/og-share-frame.png', import.meta.url)).then(
|
||||
async (res) => res.arrayBuffer(),
|
||||
),
|
||||
]);
|
||||
|
||||
const recipientOrSender = await getRecipientOrSenderByShareLinkSlug({ slug }).catch(() => null);
|
||||
const baseUrl = process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000';
|
||||
|
||||
if (!recipientOrSender) {
|
||||
const recipientOrSender: ShareHandlerAPIResponse = await fetch(
|
||||
new URL(`/api/share?slug=${slug}`, baseUrl),
|
||||
).then(async (res) => res.json());
|
||||
|
||||
if ('error' in recipientOrSender) {
|
||||
return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
@ -96,18 +108,6 @@ export async function GET(_request: Request, { params: { slug } }: SharePageOpen
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* <div
|
||||
tw="absolute flex items-center justify-center text-slate-500"
|
||||
style={{
|
||||
top: `${CARD_OFFSET_TOP + CARD_HEIGHT - 45}px`,
|
||||
left: `${CARD_OFFSET_LEFT}`,
|
||||
width: `${CARD_WIDTH}px`,
|
||||
fontSize: '30px',
|
||||
}}
|
||||
>
|
||||
{signatureName}
|
||||
</div> */}
|
||||
|
||||
<div
|
||||
tw="absolute flex flex-col items-center justify-center pt-12 w-full"
|
||||
style={{
|
||||
@ -129,7 +129,7 @@ export async function GET(_request: Request, { params: { slug } }: SharePageOpen
|
||||
</div>
|
||||
),
|
||||
{
|
||||
...size,
|
||||
...IMAGE_SIZE,
|
||||
fonts: [
|
||||
{
|
||||
name: 'Caveat',
|
||||
|
||||
@ -4,6 +4,7 @@ import { notFound } from 'next/navigation';
|
||||
import { CheckCircle2, Clock8 } from 'lucide-react';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import signingCelebration from '@documenso/assets/images/signing-celebration.png';
|
||||
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
|
||||
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
|
||||
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
|
||||
@ -13,8 +14,6 @@ import { DocumentDownloadButton } from '@documenso/ui/components/document/docume
|
||||
import { DocumentShareButton } from '@documenso/ui/components/document/document-share-button';
|
||||
import { SigningCard3D } from '@documenso/ui/components/signing-card';
|
||||
|
||||
import signingCelebration from '~/assets/signing-celebration.png';
|
||||
|
||||
export type CompletedSigningPageProps = {
|
||||
params: {
|
||||
token?: string;
|
||||
|
||||
@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
import Image from 'next/image';
|
||||
|
||||
import backgroundPattern from '~/assets/background-pattern.png';
|
||||
import backgroundPattern from '@documenso/assets/images/background-pattern.png';
|
||||
|
||||
type UnauthenticatedLayoutProps = {
|
||||
children: React.ReactNode;
|
||||
|
||||
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 215 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 743 KiB |
|
Before Width: | Height: | Size: 14 MiB |
@ -6,11 +6,10 @@ import { useRouter } from 'next/navigation';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ChevronLeft } from 'lucide-react';
|
||||
|
||||
import backgroundPattern from '@documenso/assets/images/background-pattern.png';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
|
||||
import backgroundPattern from '~/assets/background-pattern.png';
|
||||
|
||||
export type NotFoundPartialProps = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
23
apps/web/src/pages/api/share/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
|
||||
import { getRecipientOrSenderByShareLinkSlug } from '@documenso/lib/server-only/share/get-recipient-or-sender-by-share-link-slug';
|
||||
|
||||
export type ShareHandlerAPIResponse =
|
||||
| Awaited<ReturnType<typeof getRecipientOrSenderByShareLinkSlug>>
|
||||
| { error: string };
|
||||
|
||||
export default async function shareHandler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
if (typeof req.query.slug !== 'string') {
|
||||
throw new Error('Invalid slug');
|
||||
}
|
||||
|
||||
const data = await getRecipientOrSenderByShareLinkSlug({
|
||||
slug: req.query.slug,
|
||||
});
|
||||
|
||||
return res.json(data);
|
||||
} catch (error) {
|
||||
return res.status(404).json({ error: 'Not found' });
|
||||
}
|
||||
}
|
||||