Skip to content

Commit 42674bb

Browse files
committed
feat(marketing): og:image meta tags and URL-synced hero tab
Ship a real OG/Twitter card image for executor.sh and persist the hero Cloud/Local toggle to `?try=`, so the choice is shareable and survives back/forward navigation.
1 parent 4cfa299 commit 42674bb

4 files changed

Lines changed: 32 additions & 1 deletion

File tree

‎apps/marketing/astro.config.mjs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import cloudflare from "@astrojs/cloudflare";
88

99
// https://astro.build/config
1010
export default defineConfig({
11+
site: "https://executor.sh",
1112
output: "server",
1213
integrations: [react()],
1314
vite: {

‎apps/marketing/public/og-image.png‎

651 KB
Loading

‎apps/marketing/src/layouts/Layout.astro‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ const {
1010
title = 'Executor — The gateway to connect your agent to everything',
1111
description = 'One place every agent plugs into every tool you already use. Wire it up once, bring the whole team.'
1212
} = Astro.props
13+
14+
const ogImage = new URL('/og-image.png', Astro.site ?? Astro.url).toString()
15+
const canonical = new URL(Astro.url.pathname, Astro.site ?? Astro.url).toString()
1316
---
1417

1518
<html lang="en">
@@ -22,8 +25,19 @@ const {
2225
<meta name="viewport" content="width=device-width, initial-scale=1" />
2326
<meta name="color-scheme" content="light" />
2427
<meta name="description" content={description} />
28+
<link rel="canonical" href={canonical} />
29+
<meta property="og:type" content="website" />
30+
<meta property="og:url" content={canonical} />
2531
<meta property="og:title" content={title} />
2632
<meta property="og:description" content={description} />
33+
<meta property="og:image" content={ogImage} />
34+
<meta property="og:image:width" content="3800" />
35+
<meta property="og:image:height" content="2360" />
36+
<meta property="og:image:alt" content={title} />
37+
<meta name="twitter:card" content="summary_large_image" />
38+
<meta name="twitter:title" content={title} />
39+
<meta name="twitter:description" content={description} />
40+
<meta name="twitter:image" content={ogImage} />
2741
<title>{title}</title>
2842
<link rel="preconnect" href="https://fonts.googleapis.com" />
2943
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />

‎apps/marketing/src/pages/index.astro‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,16 @@ import { SelfHostContactModal } from "../components/self-host-contact-modal";
377377
// visitors still see the recommended path.
378378
const heroToggle = document.querySelector<HTMLElement>(".hero-toggle");
379379
const tabToggle = heroToggle?.querySelector<HTMLElement>(".tab-toggle");
380-
const setActiveTab = (tab: "cloud" | "local") => {
380+
const TAB_PARAM = "try";
381+
const isHeroTab = (v: unknown): v is "cloud" | "local" =>
382+
v === "cloud" || v === "local";
383+
const syncTabToUrl = (tab: "cloud" | "local") => {
384+
const url = new URL(window.location.href);
385+
if (url.searchParams.get(TAB_PARAM) === tab) return;
386+
url.searchParams.set(TAB_PARAM, tab);
387+
window.history.replaceState(window.history.state, "", url);
388+
};
389+
const setActiveTab = (tab: "cloud" | "local", updateUrl = true) => {
381390
if (!heroToggle || !tabToggle) return;
382391
heroToggle.dataset.active = tab;
383392
tabToggle.dataset.active = tab;
@@ -389,8 +398,11 @@ import { SelfHostContactModal } from "../components/self-host-contact-modal";
389398
);
390399
},
391400
);
401+
if (updateUrl) syncTabToUrl(tab);
392402
};
393403
if (heroToggle && tabToggle) {
404+
const initial = new URLSearchParams(window.location.search).get(TAB_PARAM);
405+
if (isHeroTab(initial)) setActiveTab(initial, false);
394406
tabToggle.querySelectorAll<HTMLButtonElement>("button[data-tab]").forEach(
395407
(btn) => {
396408
btn.addEventListener("click", () => {
@@ -399,6 +411,10 @@ import { SelfHostContactModal } from "../components/self-host-contact-modal";
399411
});
400412
},
401413
);
414+
window.addEventListener("popstate", () => {
415+
const next = new URLSearchParams(window.location.search).get(TAB_PARAM);
416+
setActiveTab(isHeroTab(next) ? next : "cloud", false);
417+
});
402418
}
403419

404420
// Desktop card "Download →" CTA jumps to the hero, switches to Local,

0 commit comments

Comments
 (0)