From 9b64f48c99425c6ad130c9cad9375384d0b2de5f Mon Sep 17 00:00:00 2001 From: abrichr Date: Sat, 22 Aug 2026 14:02:40 -0400 Subject: [PATCH 1/3] feat: hero demo-first CTA, evidence section reorder, newsletter capture, footer blog column - Swap hero CTAs: 'Watch it prove a result (65s)' becomes primary (scrolls to #demo); workflow-fit link becomes secondary; analytics testids and funnel events unchanged - Define qualification in plain words beside the hero CTA; rename nav button to 'Start your first workflow' (same /qualify href) - Move the three-application evidence player (#demo) above the customer case study on the homepage - Add lib/siteCopy.js canonical copy source; MastHead h1 uses buyerLine - Add NewsletterCapture (Netlify form 'newsletter', CSS-hidden honeypot, success state) mounted in Footer and near the homepage bottom - Footer: Blog column with three posts plus All posts; drop duplicate Blog entry from Connect column - netlify.toml: 301 redirects /demo -> app.openadapt.ai/demo and /docs -> docs.openadapt.ai --- components/Footer.js | 38 ++++++++- components/MastHead.js | 23 +++--- components/NavHeader.js | 2 +- components/NewsletterCapture.js | 102 ++++++++++++++++++++++++ components/NewsletterCapture.module.css | 82 +++++++++++++++++++ lib/siteCopy.js | 7 ++ netlify.toml | 13 +++ pages/index.js | 12 +-- 8 files changed, 263 insertions(+), 16 deletions(-) create mode 100644 components/NewsletterCapture.js create mode 100644 components/NewsletterCapture.module.css create mode 100644 lib/siteCopy.js diff --git a/components/Footer.js b/components/Footer.js index e22b244..c57c252 100644 --- a/components/Footer.js +++ b/components/Footer.js @@ -16,6 +16,7 @@ import { track, EVENTS } from 'utils/analytics' import repositoryStatsView from 'utils/repositoryStatsView' import repositoryStatsSelection from 'utils/repositoryStatsSelection' import useLiveRepositoryStats from 'utils/useLiveRepositoryStats' +import NewsletterCapture from './NewsletterCapture' import styles from './Footer.module.css' const { sourceLabel } = repositoryStatsView @@ -126,12 +127,28 @@ const DEVELOPER_COLUMN = [ }) const CONNECT_COLUMN = [ - BLOG_LINK, byLabel('Discord'), { label: 'GitHub', href: OPENADAPT_REPOSITORY_URL }, { label: 'Contribute workflows', href: '/contribute' }, ] +// Blog posts live on the external blog; "All posts" is the canonical +// BLOG_LINK destination shared with the top nav. +const BLOG_COLUMN = [ + { + label: 'We ran it on a real EMR', + href: 'https://blog.openadapt.ai/posts/openemr-benchmark/', + }, + { + label: 'The silent wrong write', + href: 'https://blog.openadapt.ai/posts/silent-wrong-action/', + }, + { + label: 'Compile once, govern every repair', + href: 'https://blog.openadapt.ai/posts/2026-07-20-compile-once-govern-every-repair/', + }, +] + export default function Footer({ repositoryStats = OPENADAPT_STATS_SNAPSHOT, }) { @@ -144,6 +161,7 @@ export default function Footer({ return (
+ ) +} diff --git a/components/NewsletterCapture.module.css b/components/NewsletterCapture.module.css new file mode 100644 index 0000000..85d34fa --- /dev/null +++ b/components/NewsletterCapture.module.css @@ -0,0 +1,82 @@ +.wrap { + max-width: 26rem; + margin: 0 auto 2.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.leader { + margin: 0; + font-family: var(--font-mono); + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--ink-3); +} + +.form { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; +} + +.input { + flex: 1 1 13rem; + padding: 9px 16px; + border-radius: 9999px; + border: 1px solid var(--hairline); + background: var(--panel); + color: var(--ink); + font-size: 14px; +} + +.input:focus { + outline: none; + border-color: var(--accent); +} + +.submit { + padding: 9px 20px; + border-radius: 9999px; + border: 1.5px solid var(--accent); + background: var(--accent); + color: var(--ground); + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: background-color var(--dur-2, 180ms) var(--ease-out, ease); +} + +.submit:hover { + background: var(--accent-hover); + border-color: var(--accent-hover); +} + +.submit:disabled { + opacity: 0.6; + cursor: default; +} + +.success { + margin: 0; + font-size: 14px; + color: var(--accent); +} + +.error { + margin: 0; + font-size: 13px; + color: #b42318; +} + +/* The honeypot stays in the DOM for bots but invisible to humans. */ +.hidden { + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; +} diff --git a/lib/siteCopy.js b/lib/siteCopy.js new file mode 100644 index 0000000..51c138b --- /dev/null +++ b/lib/siteCopy.js @@ -0,0 +1,7 @@ +// Canonical marketing copy. Surfaces import from here so a wording change +// can never leave two pages telling different stories about the product. +export const siteCopy = { + buyerLine: 'Automate the work your systems still make people do.', + engineLine: + 'OpenAdapt compiles demonstrated GUI workflows into deterministic, locally executable programs. Healthy runs make no model calls. When interfaces drift, OpenAdapt re-resolves from retained evidence or proposes a governed repair and halts when verification fails.', +} diff --git a/netlify.toml b/netlify.toml index 6cb0af2..e03568f 100644 --- a/netlify.toml +++ b/netlify.toml @@ -44,3 +44,16 @@ for = "/reference/*" [headers.values] Cache-Control = "public, max-age=31536000, immutable" + +# Short marketing paths for the hosted demo and the documentation site. +[[redirects]] + from = "/demo" + to = "https://app.openadapt.ai/demo" + status = 301 + force = true + +[[redirects]] + from = "/docs" + to = "https://docs.openadapt.ai" + status = 301 + force = true diff --git a/pages/index.js b/pages/index.js index b7459a3..4e944ec 100644 --- a/pages/index.js +++ b/pages/index.js @@ -8,6 +8,7 @@ import FinalQualificationCta from '@components/FinalQualificationCta' import Footer from '@components/Footer' import HowItWorksCondensed from '@components/HowItWorksCondensed' import MastHead from '@components/MastHead' +import NewsletterCapture from '@components/NewsletterCapture' import ProductStatus from '@components/ProductStatus' import Qualification from '@components/Qualification' import ReplayHero from '@components/ReplayHero' @@ -157,11 +158,6 @@ export default function Home({ githubStats, hostedOffer }) { /> -
- - - -
+
+ + + +
@@ -189,6 +190,7 @@ export default function Home({ githubStats, hostedOffer }) { +