From 9a2d69272f3dbad1ec228d0afa26808783ea3a30 Mon Sep 17 00:00:00 2001 From: BrickheadJohnny Date: Mon, 2 Dec 2024 17:18:46 +0100 Subject: [PATCH 1/2] refactor: create a separate directory for guild link previews --- .../linkpreview/[timestamp]/{[guild].tsx => [guild]/index.tsx} | 0 src/pages/api/linkpreview/[timestamp]/index.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/pages/api/linkpreview/[timestamp]/{[guild].tsx => [guild]/index.tsx} (100%) diff --git a/src/pages/api/linkpreview/[timestamp]/[guild].tsx b/src/pages/api/linkpreview/[timestamp]/[guild]/index.tsx similarity index 100% rename from src/pages/api/linkpreview/[timestamp]/[guild].tsx rename to src/pages/api/linkpreview/[timestamp]/[guild]/index.tsx diff --git a/src/pages/api/linkpreview/[timestamp]/index.tsx b/src/pages/api/linkpreview/[timestamp]/index.tsx index ef63d658ac..2c0430080e 100644 --- a/src/pages/api/linkpreview/[timestamp]/index.tsx +++ b/src/pages/api/linkpreview/[timestamp]/index.tsx @@ -9,7 +9,7 @@ export const config = { const interFont = loadGoogleFont("Inter", "400") const dystopianFont = fetch( - new URL("../../../../../public/fonts/Dystopian-Black.woff", import.meta.url) + new URL("../../../../../../public/fonts/Dystopian-Black.woff", import.meta.url) ).then((res) => res.arrayBuffer()) const handler = async (req, _) => { From 128af8cd6873dc8abcc6f84165648d75f66d38be Mon Sep 17 00:00:00 2001 From: BrickheadJohnny Date: Mon, 2 Dec 2024 18:05:27 +0100 Subject: [PATCH 2/2] feat: implement role group link previews --- src/pages/[guild]/[group].tsx | 120 ++++---- .../[timestamp]/[guild]/[group].tsx | 289 ++++++++++++++++++ .../linkpreview/[timestamp]/[guild]/index.tsx | 2 +- .../api/linkpreview/[timestamp]/index.tsx | 2 +- 4 files changed, 351 insertions(+), 62 deletions(-) create mode 100644 src/pages/api/linkpreview/[timestamp]/[guild]/[group].tsx diff --git a/src/pages/[guild]/[group].tsx b/src/pages/[guild]/[group].tsx index 6b1913a1a9..d11518a2fd 100644 --- a/src/pages/[guild]/[group].tsx +++ b/src/pages/[guild]/[group].tsx @@ -66,68 +66,61 @@ const GroupPage = (): JSX.Element => { const { localThemeColor } = useThemeContext() return ( - <> - - - - - - - - - - -
- - - + + + + + + +
+ + + + + + + + +
+ {isAdmin && isDetailed ? ( + + ) : !isMember ? ( + + ) : ( + + )} +
+
+ + {group?.description && ( + + {parseDescription(group.description)} - - - - -
- {isAdmin && isDetailed ? ( - - ) : !isMember ? ( - - ) : ( - - )} -
-
- - {group?.description && ( - - {parseDescription(group.description)} - - )} - - - - - -
: undefined} - > - -
-
- - + )} + + + + + +
: undefined} + > + +
+
+ ) } type Props = { + groupUrlName: string fallback: { string: Guild } } -const GroupPageWrapper = ({ fallback }: Props): JSX.Element => { +const GroupPageWrapper = ({ groupUrlName, fallback }: Props): JSX.Element => { const guild = useGuild() - const group = useRoleGroup() - - if (!fallback || !guild.id || !group?.id) { + if (!fallback && !guild.id) { return (
@@ -138,15 +131,21 @@ const GroupPageWrapper = ({ fallback }: Props): JSX.Element => { ) } + const [fallbackGuild] = Object.values(fallback) + const fallbackGroup = fallbackGuild?.groups.find((g) => (g.urlName = groupUrlName)) + return ( <> - - - {group.name} - - + {fallbackGuild && fallbackGroup && ( + <> + + + {fallbackGroup.name} + + + + + )} @@ -159,7 +158,7 @@ const GroupPageWrapper = ({ fallback }: Props): JSX.Element => { } const getStaticProps: GetStaticProps = async ({ params }) => { - const endpoint = `/v2/guilds/guild-page/${params.guild?.toString()}` + const endpoint = `/v2/guilds/guild-page/${params?.guild?.toString()}` const data = await fetcher(endpoint).catch((_) => ({})) @@ -183,6 +182,7 @@ const getStaticProps: GetStaticProps = async ({ params }) => { return { props: { + groupUrlName: params?.group?.toString(), fallback: { [endpoint]: filteredData, }, diff --git a/src/pages/api/linkpreview/[timestamp]/[guild]/[group].tsx b/src/pages/api/linkpreview/[timestamp]/[guild]/[group].tsx new file mode 100644 index 0000000000..b50f4fb18b --- /dev/null +++ b/src/pages/api/linkpreview/[timestamp]/[guild]/[group].tsx @@ -0,0 +1,289 @@ +import { env } from "env" +import loadGoogleFont from "fonts/loadGoogleFont" +import { ImageResponse } from "next/og" +import { Guild } from "types" + +export const config = { + runtime: "edge", +} + +const interFont = loadGoogleFont("Inter", "400") +const interBoldFont = loadGoogleFont("Inter", "700") +const dystopianFont = fetch( + new URL("../../../../../../public/fonts/Dystopian-Black.woff", import.meta.url) +).then((res) => res.arrayBuffer()) + +const handler = async (req, _) => { + const { protocol, host } = req.nextUrl + const baseUrl = `${protocol}//${host}` + + const [, urlName, groupUrlName] = + req.nextUrl?.pathname + ?.replace("/api/linkpreview", "") + ?.split("/") + ?.filter((param) => !!param) ?? [] + + if (!urlName || !groupUrlName) return new ImageResponse(<>, { status: 404 }) + + const [guild, groups, guildRoles]: [Guild, Guild["groups"], Guild["roles"]] = + await Promise.all([ + fetch(`${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${urlName}`).then( + (res) => res.json() + ), + fetch( + `${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${urlName}/groups` + ).then((res) => res.json()), + fetch( + `${env.NEXT_PUBLIC_API.replace("v1", "v2")}/guilds/${urlName}/roles` + ).then((res) => res.json()), + ]).catch(() => [null, null, null]) + + if (!guild?.id) + return new Response(undefined, { + status: 404, + statusText: "Guild not found", + }) + + const group = groups?.find((g) => g.urlName === groupUrlName) + + if (!group) + return new Response(undefined, { + status: 404, + statusText: "Group not found", + }) + + try { + const [interFontData, interBoldFontData, dystopianFontData] = await Promise.all([ + interFont, + interBoldFont, + dystopianFont, + ]) + + const roles = guildRoles?.map((role) => role.name) + + const safeGroupDescription = group.description?.replaceAll("\n", "") + + const imageUrl = group.imageUrl ?? guild.imageUrl + + return new ImageResponse( +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + Guilders + +
+ +
+
+
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {group.name} +
+

+ {group.name} +

+
+ +
+
{`${new Intl.NumberFormat("en", { notation: "compact" }).format( + guild?.memberCount ?? 0 + )} members`}
+ +
{`${roles?.length || 0} roles`}
+
+ +
+ {group.description ? ( + `${safeGroupDescription?.slice(0, 80)}${ + (safeGroupDescription?.length ?? 0) > 80 ? "..." : "" + }` + ) : ( +
+
+ {"That's a great party in there!"} +
+
{"I dare you to be the plus one."}
+
+ )} +
+ +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + Guild.xyz +
+ Guild.xyz +
+
+
+
, + { + width: 800, + height: 450, + fonts: [ + { + name: "Inter", + data: interFontData, + style: "normal", + weight: 400, + }, + { + name: "Inter", + data: interBoldFontData, + style: "normal", + weight: 700, + }, + { + name: "Dystopian", + data: dystopianFontData, + style: "normal", + }, + ], + } + ) + } catch (e: any) {} +} + +export default handler diff --git a/src/pages/api/linkpreview/[timestamp]/[guild]/index.tsx b/src/pages/api/linkpreview/[timestamp]/[guild]/index.tsx index 0719805e99..59f32dabf9 100644 --- a/src/pages/api/linkpreview/[timestamp]/[guild]/index.tsx +++ b/src/pages/api/linkpreview/[timestamp]/[guild]/index.tsx @@ -10,7 +10,7 @@ export const config = { const interFont = loadGoogleFont("Inter", "400") const interBoldFont = loadGoogleFont("Inter", "700") const dystopianFont = fetch( - new URL("../../../../../public/fonts/Dystopian-Black.woff", import.meta.url) + new URL("../../../../../../public/fonts/Dystopian-Black.woff", import.meta.url) ).then((res) => res.arrayBuffer()) const handler = async (req, _) => { diff --git a/src/pages/api/linkpreview/[timestamp]/index.tsx b/src/pages/api/linkpreview/[timestamp]/index.tsx index 2c0430080e..ef63d658ac 100644 --- a/src/pages/api/linkpreview/[timestamp]/index.tsx +++ b/src/pages/api/linkpreview/[timestamp]/index.tsx @@ -9,7 +9,7 @@ export const config = { const interFont = loadGoogleFont("Inter", "400") const dystopianFont = fetch( - new URL("../../../../../../public/fonts/Dystopian-Black.woff", import.meta.url) + new URL("../../../../../public/fonts/Dystopian-Black.woff", import.meta.url) ).then((res) => res.arrayBuffer()) const handler = async (req, _) => {