diff --git a/web/app/modules/article.tsx b/web/app/modules/article.tsx
index ae56e6d4..b7078fc8 100644
--- a/web/app/modules/article.tsx
+++ b/web/app/modules/article.tsx
@@ -3,6 +3,7 @@ import { mergeMeta } from "./meta";
import { InfoPill } from "./info-pill";
import clsx from "clsx";
import { InfoCard } from "./info-card";
+import { BASE_URL } from "./app";
export type NewsArticleHandle = {
slug: string;
@@ -20,6 +21,10 @@ export const composeArticleMeta = mergeMeta(({ matches }) => {
return [
{ title: `${article?.title} | CRAN/E` },
{ name: "description", content: article?.subline },
+ { property: "og:title", content: `${article?.title} | CRAN/E` },
+ { property: "og:url", content: `${BASE_URL}/press/news/${article?.slug}` },
+ { property: "og:description", content: article?.subline },
+ { property: "og:image", content: `${BASE_URL}/press/news/og` },
];
});
diff --git a/web/app/modules/contact-pill.tsx b/web/app/modules/contact-pill.tsx
index dcfd1b0e..b79f54b1 100644
--- a/web/app/modules/contact-pill.tsx
+++ b/web/app/modules/contact-pill.tsx
@@ -62,7 +62,7 @@ export function ContactPill(props: Props) {
className="text-gold-1 dark:text-gold-2"
/>
}
- className="border-transparent bg-gold-10 text-gold-1 dark:bg-gold-11 dark:text-gold-2"
+ className="border-transparent text-gold-1 dark:bg-gold-12"
>
Maintainer
diff --git a/web/app/modules/footer.tsx b/web/app/modules/footer.tsx
index 509edb98..d1acdd40 100644
--- a/web/app/modules/footer.tsx
+++ b/web/app/modules/footer.tsx
@@ -3,7 +3,6 @@ import { ExternalLink } from "./external-link";
import { cva, VariantProps } from "cva";
import { ReactNode } from "react";
import clsx from "clsx";
-import { RiGithubLine } from "@remixicon/react";
const BASE_ITEMS: Array<{ label: string; href: string }> = [
{ label: "About", href: "/about" },
@@ -53,12 +52,11 @@ export function Footer(props: Props) {
href="https://github.com/flaming-codes/crane-app"
className="underline-offset-4 hover:brightness-75"
>
-
- Github
+ Github
{version && (
-
+
v{version}
diff --git a/web/app/modules/meta-og-image.server.tsx b/web/app/modules/meta-og-image.server.tsx
new file mode 100644
index 00000000..a41c5e28
--- /dev/null
+++ b/web/app/modules/meta-og-image.server.tsx
@@ -0,0 +1,139 @@
+// ./app/utils/createOGImage.server.tsx
+
+import { Resvg } from "@resvg/resvg-js";
+import type { SatoriOptions } from "satori";
+import satori from "satori";
+
+const OG_IMAGE_HEIGHT = 630;
+const OG_IMAGE_WIDTH = 1200;
+
+function getRegularSans(baseUrl: string) {
+ return fetch(new URL(`${baseUrl}/fonts/Inter-Regular.ttf`)).then(
+ async (res) => {
+ return res.arrayBuffer();
+ },
+ );
+}
+
+async function getBaseOptions(
+ requestUrl: string,
+ partial: Partial = {},
+): Promise {
+ const fontSansData = await getRegularSans(requestUrl);
+
+ return {
+ width: OG_IMAGE_WIDTH,
+ height: OG_IMAGE_HEIGHT,
+ fonts: [
+ {
+ name: "Inter",
+ data: fontSansData,
+ weight: 400,
+ style: "normal",
+ },
+ ],
+ ...partial,
+ };
+}
+
+export async function composeAuthorOGImage(params: {
+ name: string;
+ requestUrl: string;
+}) {
+ const { name, requestUrl } = params;
+
+ // Design the image and generate an SVG with "satori"
+ const svg = await satori(
+
+ {name}
+
,
+ await getBaseOptions(requestUrl),
+ );
+
+ return new Resvg(svg).render().asPng();
+}
+
+export async function composePackageOGImage(params: {
+ name: string;
+ requestUrl: string;
+}) {
+ const { name, requestUrl } = params;
+
+ // Design the image and generate an SVG with "satori"
+ const svg = await satori(
+
+ {name}
+
,
+ await getBaseOptions(requestUrl),
+ );
+
+ return new Resvg(svg).render().asPng();
+}
+
+export async function composeNewsArticleOGImage(params: {
+ headline: string;
+ subline?: string;
+ requestUrl: string;
+}) {
+ const { headline, subline, requestUrl } = params;
+
+ // Design the image and generate an SVG with "satori"
+ const svg = await satori(
+
+ {headline}
+ {subline ? (
+ {subline}
+ ) : null}
+
,
+ await getBaseOptions(requestUrl),
+ );
+
+ return new Resvg(svg).render().asPng();
+}
diff --git a/web/app/modules/meta.ts b/web/app/modules/meta.ts
index d1821a2a..7aa34ca6 100644
--- a/web/app/modules/meta.ts
+++ b/web/app/modules/meta.ts
@@ -42,6 +42,8 @@ export const mergeMeta = (
);
if (index !== -1) {
mergedMeta.splice(index, 1, override);
+ } else {
+ mergedMeta.push(override);
}
}
diff --git a/web/app/modules/svg.tsx b/web/app/modules/svg.tsx
index 32ebdba2..5a02fd6c 100644
--- a/web/app/modules/svg.tsx
+++ b/web/app/modules/svg.tsx
@@ -1,13 +1,17 @@
+import { CSSProperties } from "react";
+
type Props = {
className?: string;
+ style?: CSSProperties;
};
-export function SineLogo({ className }: Props) {
+export function SineLogo({ className, style }: Props) {
return (