Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,48 +1,15 @@
import { Img } from "@/components/blocks/Img";
import { useMemo } from "react";
import type { ThirdwebClient } from "thirdweb";
import { resolveSchemeWithErrorHandler } from "../../../lib/resolveSchemeWithErrorHandler";
import { cn } from "../../../lib/utils";

const gradients = [
["#fca5a5", "#b91c1c"],
["#fdba74", "#c2410c"],
["#fcd34d", "#b45309"],
["#fde047", "#a16207"],
["#a3e635", "#4d7c0f"],
["#86efac", "#15803d"],
["#67e8f9", "#0e7490"],
["#7dd3fc", "#0369a1"],
["#93c5fd", "#1d4ed8"],
["#a5b4fc", "#4338ca"],
["#c4b5fd", "#6d28d9"],
["#d8b4fe", "#7e22ce"],
["#f0abfc", "#a21caf"],
["#f9a8d4", "#be185d"],
["#fda4af", "#be123c"],
];

function getGradientForString(str: string) {
const number = Math.abs(
str.split("").reduce((acc, b, i) => acc + b.charCodeAt(0) * (i + 1), 0),
);
const index = number % gradients.length;
return gradients[index];
}
import { GradientBlobbie } from "./GradientBlobbie";

export function GradientAvatar(props: {
src: string | undefined;
id: string | undefined;
className: string;
client: ThirdwebClient;
}) {
const gradient = useMemo(() => {
if (!props.id) {
return undefined;
}
return getGradientForString(props.id);
}, [props.id]);

const resolvedSrc = props.src
? resolveSchemeWithErrorHandler({
client: props.client,
Expand All @@ -54,15 +21,7 @@ export function GradientAvatar(props: {
<Img
src={resolvedSrc}
className={cn("rounded-full", props.className)}
fallback={
gradient ? (
<div
style={{
background: `linear-gradient(45deg, ${gradient[0]} 0%, ${gradient[1]} 100%)`,
}}
/>
) : undefined
}
fallback={props.id ? <GradientBlobbie id={props.id} /> : undefined}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Note: This is also used in opengraph-image.tsx
// don't use any hooks or client side stuff here

const gradients = [
["#fca5a5", "#b91c1c"],
["#fdba74", "#c2410c"],
["#fcd34d", "#b45309"],
["#fde047", "#a16207"],
["#a3e635", "#4d7c0f"],
["#86efac", "#15803d"],
["#67e8f9", "#0e7490"],
["#7dd3fc", "#0369a1"],
["#93c5fd", "#1d4ed8"],
["#a5b4fc", "#4338ca"],
["#c4b5fd", "#6d28d9"],
["#d8b4fe", "#7e22ce"],
["#f0abfc", "#a21caf"],
["#f9a8d4", "#be185d"],
["#fda4af", "#be123c"],
];

function getGradientForString(str: string) {
const number = Math.abs(
str.split("").reduce((acc, b, i) => acc + b.charCodeAt(0) * (i + 1), 0),
);
const index = number % gradients.length;
return gradients[index];
}

export function GradientBlobbie(props: {
id: string;
style?: React.CSSProperties;
}) {
const gradient = getGradientForString(props.id);
return (
<div
style={{
...props.style,
background: gradient
? `linear-gradient(45deg, ${gradient[0]} 0%, ${gradient[1]} 100%)`
: undefined,
}}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { GradientBlobbie } from "@/components/blocks/Avatars/GradientBlobbie";
/* eslint-disable @next/next/no-img-element */
import { getThirdwebClient } from "@/constants/thirdweb.server";
import { resolveSchemeWithErrorHandler } from "@/lib/resolveSchemeWithErrorHandler";
import { notFound } from "next/navigation";
import { ImageResponse } from "next/og";
import { resolveAvatar } from "thirdweb/extensions/ens";
import { shortenIfAddress } from "../../../../utils/usedapp-external";
import { resolveAddressAndEns } from "./resolveAddressAndEns";

export const runtime = "edge";

export const size = {
width: 1200,
height: 630,
};

type PageProps = {
params: Promise<{
addressOrEns: string;
}>;
};

export default async function Image(props: PageProps) {
const client = getThirdwebClient();
const params = await props.params;
const resolvedInfo = await resolveAddressAndEns(params.addressOrEns);

if (!resolvedInfo) {
notFound();
}

const [inter700, profileBackground] = await Promise.all([
fetch(new URL("og-lib/fonts/inter/700.ttf", import.meta.url)).then((res) =>
res.arrayBuffer(),
),
fetch(
new URL("og-lib/assets/profile/background.png", import.meta.url),
).then((res) => res.arrayBuffer()),
]);

const ensImage = resolvedInfo.ensName
? await resolveAvatar({
client: client,
name: resolvedInfo.ensName,
})
: null;

const resolvedENSImageSrc = ensImage
? resolveSchemeWithErrorHandler({
client: client,
uri: ensImage,
})
: null;

return new ImageResponse(
<div
tw="w-full h-full flex justify-center py-20 px-16"
style={{
background: "#0D0D12",
fontFamily: "Inter",
}}
>
<img
// @ts-expect-error - this works fine
src={profileBackground}
width="1200px"
height="630px"
tw="absolute"
alt=""
/>

<div tw="w-full h-full flex flex-col justify-between">
<div tw="flex flex-col w-full">
{resolvedENSImageSrc ? (
<img alt="" tw="w-32 h-32 rounded-full" src={resolvedENSImageSrc} />
) : (
<GradientBlobbie
id={resolvedInfo.address}
style={{
width: "128px",
height: "128px",
borderRadius: "50%",
}}
/>
)}

<h1 tw="text-7xl text-white font-bold my-5">
{resolvedInfo.ensName || shortenIfAddress(resolvedInfo.address)}
</h1>
</div>
<div tw="flex justify-end w-full items-end">
<div tw="flex flex-shrink-0">
<OgBrandIcon />
</div>
</div>
</div>
</div>,
{
...size,
fonts: [
{
data: inter700,
name: "Inter",
weight: 700,
},
],
},
);
}

const OgBrandIcon: React.FC = () => (
// biome-ignore lint/a11y/noSvgWithoutTitle: not needed
<svg
xmlns="http://www.w3.org/2000/svg"
width="59"
height="36"
viewBox="0 0 59 36"
fill="none"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M0.157801 3.02898C-0.425237 1.57299 0.661334 0 2.25144 0H12.1233C13.0509 0 13.8725 0.545996 14.217 1.39099L22.0747 20.7869C22.2868 21.3068 22.2868 21.8918 22.0747 22.4248L17.1322 34.6058C16.3769 36.4647 13.7002 36.4647 12.9449 34.6058L0.157801 3.02898ZM19.227 2.96398C18.697 1.52099 19.7835 0 21.3471 0H29.9469C30.901 0 31.7491 0.584996 32.0671 1.45599L39.2093 20.8519C39.3816 21.3328 39.3816 21.8658 39.2093 22.3598L34.916 34.0208C34.2005 35.9707 31.3913 35.9707 30.6757 34.0208L19.227 2.96398ZM38.5336 0C36.9435 0 35.8569 1.57299 36.4399 3.02898L49.227 34.6058C49.9823 36.4647 52.659 36.4647 53.4143 34.6058L58.3569 22.4248C58.5689 21.8918 58.5689 21.3068 58.3569 20.7869L50.4991 1.39099C50.1546 0.545996 49.333 0 48.4055 0H38.5336Z"
fill="white"
fillOpacity="0.5"
/>
</svg>
);
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,15 @@ export async function generateMetadata(props: PageProps): Promise<Metadata> {
replaceDeployerAddress(resolvedInfo.ensName || resolvedInfo.address),
);

const title = displayName;
const description = `Visit ${displayName}'s profile. See their published contracts and deploy them in one click.`;

return {
title: displayName,
description: `Visit ${displayName}'s profile. See their published contracts and deploy them in one click.`,
title,
description,
openGraph: {
title,
description,
},
};
}
56 changes: 0 additions & 56 deletions apps/dashboard/src/og-lib/url-utils.ts

This file was deleted.

Loading
Loading