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 */}
+
+
+
+
+
+
+
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+
+
+
+ {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
+
+
+
+
,
+ {
+ 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].tsx b/src/pages/api/linkpreview/[timestamp]/[guild]/index.tsx
similarity index 98%
rename from src/pages/api/linkpreview/[timestamp]/[guild].tsx
rename to src/pages/api/linkpreview/[timestamp]/[guild]/index.tsx
index 0719805e99..59f32dabf9 100644
--- a/src/pages/api/linkpreview/[timestamp]/[guild].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, _) => {