| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | --- | 1 | --- |
| 2 | import { Image } from "astro:assets"; | 2 | import { getImage, Image } from "astro:assets"; |
| 3 | import appIcon from "../assets/icon.webp"; | 3 | import appIcon from "../assets/icon.webp"; |
| | 4 | import desktopScreenshot from "../assets/app-desktop.webp"; |
| 4 | import dmSansLatinUrl from "../assets/fonts/dm-sans-latin.woff2?url"; | 5 | import dmSansLatinUrl from "../assets/fonts/dm-sans-latin.woff2?url"; |
| 5 | import "../styles/fonts.css"; | 6 | import "../styles/fonts.css"; |
| 6 | import { | 7 | import { |
| ... | @@ -21,6 +22,21 @@ const { | ... | @@ -21,6 +22,21 @@ const { |
| 21 | description = "T3 Code. The open-source control plane for coding agents.", | 22 | description = "T3 Code. The open-source control plane for coding agents.", |
| 22 | pageClass, | 23 | pageClass, |
| 23 | } = Astro.props; | 24 | } = Astro.props; |
| | 25 | |
| | 26 | // Social preview card. Link unfurlers (Instagram, iMessage, X, Slack) want a |
| | 27 | // 1200x630 jpg or png at an absolute URL. Built from the hero screenshot so it |
| | 28 | // stays in sync with the homepage. |
| | 29 | const socialImage = await getImage({ |
| | 30 | src: desktopScreenshot, |
| | 31 | width: 1200, |
| | 32 | height: 630, |
| | 33 | fit: "cover", |
| | 34 | position: "top", |
| | 35 | format: "jpg", |
| | 36 | quality: 90, |
| | 37 | }); |
| | 38 | const socialImageUrl = new URL(socialImage.src, Astro.site); |
| | 39 | const canonicalUrl = new URL(Astro.url.pathname, Astro.site); |
| 24 | --- | 40 | --- |
| 25 | | 41 | |
| 26 | <html lang="en"> | 42 | <html lang="en"> |
| ... | @@ -28,6 +44,21 @@ const { | ... | @@ -28,6 +44,21 @@ const { |
| 28 | <meta charset="UTF-8" /> | 44 | <meta charset="UTF-8" /> |
| 29 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | 45 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| 30 | <meta name="description" content={description} /> | 46 | <meta name="description" content={description} /> |
| | 47 | <link rel="canonical" href={canonicalUrl} /> |
| | 48 | <meta property="og:type" content="website" /> |
| | 49 | <meta property="og:site_name" content="T3 Code" /> |
| | 50 | <meta property="og:url" content={canonicalUrl} /> |
| | 51 | <meta property="og:title" content={title} /> |
| | 52 | <meta property="og:description" content={description} /> |
| | 53 | <meta property="og:image" content={socialImageUrl} /> |
| | 54 | <meta property="og:image:width" content="1200" /> |
| | 55 | <meta property="og:image:height" content="630" /> |
| | 56 | <meta property="og:image:alt" content="The T3 Code desktop app with a thread open." /> |
| | 57 | <meta name="twitter:card" content="summary_large_image" /> |
| | 58 | <meta name="twitter:site" content="@t3dotgg" /> |
| | 59 | <meta name="twitter:title" content={title} /> |
| | 60 | <meta name="twitter:description" content={description} /> |
| | 61 | <meta name="twitter:image" content={socialImageUrl} /> |
| 31 | <link | 62 | <link |
| 32 | rel="preload" | 63 | rel="preload" |
| 33 | href={dmSansLatinUrl} | 64 | href={dmSansLatinUrl} |