diff --git a/apps/landing/src/pages/blog/[slug].tsx b/apps/landing/src/pages/blog/[slug].tsx index efb676638..544f2f12e 100644 --- a/apps/landing/src/pages/blog/[slug].tsx +++ b/apps/landing/src/pages/blog/[slug].tsx @@ -31,7 +31,11 @@ const Page: NextPageWithLayout = ({ post }) => { return (
- - -
- - {!hideNav ? : null} - - - - {children} - - -
- {isFeedbackEnabled ? ( - <> - - - - ) : null} -
- + + + + +
+ + {!hideNav ? : null} + + + + {children} + + +
+ {isFeedbackEnabled ? ( + <> + + + + ) : null} +
+
+
); }; diff --git a/apps/web/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx index 72e39ab61..fd3dad3bc 100644 --- a/apps/web/src/pages/_app.tsx +++ b/apps/web/src/pages/_app.tsx @@ -16,8 +16,6 @@ import { DefaultSeo } from "next-seo"; import React from "react"; import Maintenance from "@/components/maintenance"; -import { UserProvider } from "@/components/user-provider"; -import { DayjsProvider } from "@/utils/dayjs"; import * as nextI18nNextConfig from "../../next-i18next.config.js"; import { NextPageWithLayout } from "../types"; @@ -95,13 +93,9 @@ const MyApp: NextPage = ({ Component, pageProps }) => { --font-inter: ${inter.style.fontFamily}; } `} - - - - {getLayout()} - - - + + {getLayout()} + ); }; diff --git a/apps/web/src/pages/api/og-image-poll.tsx b/apps/web/src/pages/api/og-image-poll.tsx new file mode 100644 index 000000000..935a04df4 --- /dev/null +++ b/apps/web/src/pages/api/og-image-poll.tsx @@ -0,0 +1,90 @@ +/* eslint-disable @next/next/no-img-element */ +import { ImageResponse } from "@vercel/og"; +import { NextRequest } from "next/server"; +import { z } from "zod"; + +const schema = z.object({ + title: z.string().min(1), + author: z.string().min(1), +}); + +export const config = { + runtime: "edge", +}; + +const regularFont = fetch( + new URL("/public/static/fonts/inter-regular.ttf", import.meta.url), +).then((res) => res.arrayBuffer()); + +const boldFont = fetch( + new URL("/public/static/fonts/inter-bold.ttf", import.meta.url), +).then((res) => res.arrayBuffer()); + +export default async function handler(req: NextRequest) { + const [regularFontData, boldFontData] = await Promise.all([ + regularFont, + boldFont, + ]); + const { searchParams } = req.nextUrl; + + const { title, author } = schema.parse({ + title: searchParams.get("title"), + author: searchParams.get("author"), + }); + + return new ImageResponse( + ( +
+
+
+ Rallly +
+ Invite +
+
+
+
+ By {author} +
+
+ {title} +
+
+
+
+ ), + { + width: 1200, + height: 630, + fonts: [ + { + name: "Inter", + data: regularFontData, + weight: 400, + }, + { + name: "Inter", + data: boldFontData, + weight: 700, + }, + ], + }, + ); +} diff --git a/apps/web/src/pages/auth/disable-notifications.tsx b/apps/web/src/pages/auth/disable-notifications.tsx index 188770f90..c3bfbda91 100644 --- a/apps/web/src/pages/auth/disable-notifications.tsx +++ b/apps/web/src/pages/auth/disable-notifications.tsx @@ -14,7 +14,9 @@ import React from "react"; import { useMount } from "react-use"; import { AuthLayout } from "@/components/layouts/auth-layout"; +import { StandardLayout } from "@/components/layouts/standard-layout"; import { Spinner } from "@/components/spinner"; +import { NextPageWithLayout } from "@/types"; import { usePostHog } from "@/utils/posthog"; import { withPageTranslations } from "@/utils/with-page-translations"; @@ -69,7 +71,7 @@ type PageProps = } | { error: undefined; data: Data }; -const Page = (props: PageProps) => { +const Page: NextPageWithLayout = (props) => { const { t } = useTranslation(); const posthog = usePostHog(); @@ -101,6 +103,10 @@ const Page = (props: PageProps) => { ); }; +Page.getLayout = (page) => { + return {page}; +}; + export const getServerSideProps = composeGetServerSideProps( withPageTranslations(), withSessionSsr(async (ctx) => { diff --git a/apps/web/src/pages/invite/[urlId].tsx b/apps/web/src/pages/invite/[urlId].tsx index 93452a0a8..0c7053f2b 100644 --- a/apps/web/src/pages/invite/[urlId].tsx +++ b/apps/web/src/pages/invite/[urlId].tsx @@ -1,18 +1,24 @@ import { trpc } from "@rallly/backend"; +import { prisma } from "@rallly/database"; import { ArrowUpLeftIcon } from "@rallly/icons"; import { Button } from "@rallly/ui/button"; +import { absoluteUrl } from "@rallly/utils"; +import { GetStaticProps } from "next"; import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; +import { useTranslation } from "next-i18next"; +import { NextSeo } from "next-seo"; import React from "react"; import { Poll } from "@/components/poll"; import { LegacyPollContextProvider } from "@/components/poll/poll-context-provider"; import { Trans } from "@/components/trans"; -import { useUser } from "@/components/user-provider"; +import { UserProvider, useUser } from "@/components/user-provider"; import { VisibilityProvider } from "@/components/visibility"; import { PermissionsContext } from "@/contexts/permissions"; import { usePoll } from "@/contexts/poll"; +import { DayjsProvider } from "@/utils/dayjs"; import { getStaticTranslations } from "@/utils/with-page-translations"; import Error404 from "../404"; @@ -79,70 +85,136 @@ const GoToApp = () => { ); }; -const Page = () => { +type PageProps = { + title: string; + user: string | null; +}; + +const Page = ({ title, user }: PageProps) => { + const { t } = useTranslation(); + const name = user ?? t("guest"); return ( - - - -
- -
- - -
-
- + + + + + + +
+ +
+ + +
+
+ + ), + }} /> - ), - }} - /> +
+
+
-
-
-
- - - + + + + + + ); }; export const getStaticPaths = async () => { return { - paths: [], //indicates that no page needs be created at build time - fallback: "blocking", //indicates the type of fallback + paths: [], // indicates that no page needs be created at build time + fallback: "blocking", // indicates the type of fallback }; }; -export const getStaticProps = getStaticTranslations; +export const getStaticProps: GetStaticProps = async (ctx) => { + // We get these props to be able to render the og:image + const poll = await prisma.poll.findUniqueOrThrow({ + where: { + id: ctx.params?.urlId as string, + }, + select: { + title: true, + user: { + select: { + name: true, + }, + }, + }, + }); + + const res = await getStaticTranslations(ctx); + + if ("props" in res) { + return { + props: { + ...res.props, + title: poll.title, + user: poll.user?.name ?? null, + }, + revalidate: 10, + }; + } + + return res; +}; export default Page;