Refresh homepage messaging and Product Hunt banner (#402)

This commit is contained in:
Ben Senescu 2026-07-19 00:59:39 -04:00 committed by GitHub
parent cd550729a2
commit 20d3de0e08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 31 additions and 52 deletions

View File

@ -10,6 +10,7 @@ data, or sensitive paths.
## Open ## Open
- [ ] `2026-07-19T04:06:52Z``codex``pnpm --dir web build` fails with `vite: command not found` when `web/node_modules` is absent, despite the root toolchain being installed. Document or enforce the package-local install required before validating the `web/` subpackage.
- [ ] `2026-07-19T02:55:56Z``claude` — Adding a docs folder under `web/content/docs` whose `meta.json` lists an `[Overview](...)` link renders a duplicated, double-highlighted sidebar entry, because the folder-index strip in `web/src/lib/source.ts` (`transformPageTree.folder`) is a per-folder-name allowlist. Derive it from the meta convention (or strip the index for all folders) so new sections don't need a hidden source.ts edit. - [ ] `2026-07-19T02:55:56Z``claude` — Adding a docs folder under `web/content/docs` whose `meta.json` lists an `[Overview](...)` link renders a duplicated, double-highlighted sidebar entry, because the folder-index strip in `web/src/lib/source.ts` (`transformPageTree.folder`) is a per-folder-name allowlist. Derive it from the meta convention (or strip the index for all folders) so new sections don't need a hidden source.ts edit.
- [ ] `2026-07-14T01:28:30Z``claude` — Regenerating the lockfile (adding or moving a dep) makes `pnpm install` re-run the `minimumReleaseAge` gate on transitive peers already pinned at that exact version (`mysql2`, `sql-escaper`, `@aws-sdk/credential-providers`), failing the install even though nothing about them changed. `pnpm install --config.minimumReleaseAge=0` — then confirm the lockfile diff stays version-neutral — unblocks it; worth documenting that regen step so the gate doesn't re-block already-pinned versions. - [ ] `2026-07-14T01:28:30Z``claude` — Regenerating the lockfile (adding or moving a dep) makes `pnpm install` re-run the `minimumReleaseAge` gate on transitive peers already pinned at that exact version (`mysql2`, `sql-escaper`, `@aws-sdk/credential-providers`), failing the install even though nothing about them changed. `pnpm install --config.minimumReleaseAge=0` — then confirm the lockfile diff stays version-neutral — unblocks it; worth documenting that regen step so the gate doesn't re-block already-pinned versions.
- [ ] `2026-07-10T21:28:46Z``codex``pnpm --dir badseo run typecheck` works through the root toolchain but `pnpm --dir badseo run build` can't find Vite because `badseo/node_modules` is absent. Document or enforce the package-local install before validating the `badseo/` subpackage. - [ ] `2026-07-10T21:28:46Z``codex``pnpm --dir badseo run typecheck` works through the root toolchain but `pnpm --dir badseo run build` can't find Vite because `badseo/node_modules` is absent. Document or enforce the package-local install before validating the `badseo/` subpackage.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -97,22 +97,6 @@
margin: 0; margin: 0;
text-wrap: balance; text-wrap: balance;
} }
/* Desktop keeps the headline on two lines via a forced break; mobile wraps
naturally (the break is removed below the tablet breakpoint). */
.itc-h1-br {
display: inline;
}
@media (max-width: 767px) {
.itc-h1-br {
display: none;
}
}
@media (min-width: 768px) {
/* Let the forced <br> own the break; don't let balance re-split into 3 lines. */
.itc-display-xl {
text-wrap: wrap;
}
}
.itc-display-lg { .itc-display-lg {
font-size: clamp(32px, 4.4vw, 52px); font-size: clamp(32px, 4.4vw, 52px);
font-weight: 500; font-weight: 500;
@ -318,34 +302,12 @@
color: var(--ink); color: var(--ink);
transition: color 0.18s ease; transition: color 0.18s ease;
} }
.itc-hero-title-accent {
color: inherit;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
}
.itc-hero-subtitle { .itc-hero-subtitle {
transition: transition:
background-color 0.18s ease, background-color 0.18s ease,
border-color 0.18s ease, border-color 0.18s ease,
color 0.18s ease; color 0.18s ease;
} }
.itc-hero-subtitle-counter,
.itc-hero-subtitle-win {
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
font-style: italic;
transition:
background-color 0.18s ease,
color 0.18s ease,
text-decoration-color 0.18s ease;
}
.itc-hero-subtitle-counter {
color: #7a746d;
}
.itc-hero-subtitle-win {
color: var(--orange);
font-weight: 500;
}
@media (max-width: 767px) { @media (max-width: 767px) {
.itc-hero { .itc-hero {
min-height: calc(100svh - 120px); min-height: calc(100svh - 120px);

View File

@ -196,24 +196,15 @@ function Hero() {
className="itc-display-xl itc-hero-title" className="itc-display-xl itc-hero-title"
style={{ maxWidth: 1180, margin: "0 auto" }} style={{ maxWidth: 1180, margin: "0 auto" }}
> >
Say goodbye to{" "} The modern, open source SEO platform.
<span className="itc-hero-title-accent">bloated,</span>{" "}
<br className="itc-h1-br" />
<span className="itc-hero-title-accent">overpriced SEO tools.</span>
</h1> </h1>
<p <p
className="itc-subhead itc-muted itc-hero-subtitle" className="itc-subhead itc-muted itc-hero-subtitle"
style={{ maxWidth: 640, margin: "24px auto 0" }} style={{ maxWidth: 640, margin: "24px auto 0" }}
> >
Speed up strategy decisions with quality SEO data for every workflow, Without quality data, AI gives generic advice. OpenSEO is built for
all in one place.{" "} you and your AI agent to work together on SEO strategy + content
<span className="itc-hero-subtitle-counter"> tailored to your business.
Don&apos;t put SEO on autopilot
</span>
,{" "}
<span className="itc-hero-subtitle-win">
work with your AI agent to actually win.
</span>
</p> </p>
<div className="itc-hero-ctas"> <div className="itc-hero-ctas">
<div className="itc-hero-cta-group"> <div className="itc-hero-cta-group">
@ -237,7 +228,7 @@ function Testimonial() {
className="itc-display-md itc-testimonials-title" className="itc-display-md itc-testimonials-title"
style={{ margin: "0 auto 32px" }} style={{ margin: "0 auto 32px" }}
> >
Trusted by customers all over the world Trusted by hundreds of customers worldwide
</h2> </h2>
<div className="itc-quote-grid"> <div className="itc-quote-grid">
{TESTIMONIALS.map((t) => ( {TESTIMONIALS.map((t) => (

View File

@ -10,6 +10,8 @@ import { SiteFooter } from "@/components/site-footer";
import { featureGroups } from "@/lib/feature-pages"; import { featureGroups } from "@/lib/feature-pages";
const GITHUB_REPO = "every-app/open-seo"; const GITHUB_REPO = "every-app/open-seo";
const PRODUCT_HUNT_URL =
"https://www.producthunt.com/products/openseo?launch=openseo";
// Used if GitHub is unreachable at build time so the header never renders empty. // Used if GitHub is unreachable at build time so the header never renders empty.
const FALLBACK_STAR_COUNT = "2.1k"; const FALLBACK_STAR_COUNT = "2.1k";
@ -157,6 +159,23 @@ function MarketingLayout() {
return ( return (
<main className="min-h-screen bg-[var(--color-surface)] text-[var(--color-brand)]"> <main className="min-h-screen bg-[var(--color-surface)] text-[var(--color-brand)]">
{isHome ? (
<a
href={PRODUCT_HUNT_URL}
target="_blank"
rel="noopener noreferrer"
className="group flex min-h-11 items-center justify-center gap-2 bg-[#ff6154] px-4 py-2.5 text-center text-sm font-semibold text-white transition-colors hover:bg-[#e9574c] focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-white"
aria-label="OpenSEO just launched on Product Hunt. Upvote and comment."
>
<span className="inline-flex size-6 shrink-0 items-center justify-center rounded-full bg-white p-0.5">
<img src="/product-hunt.svg" alt="" className="size-full" />
</span>
<span>OpenSEO just launched on Product Hunt.</span>
<span className="inline-flex items-center gap-1 whitespace-nowrap underline decoration-white/55 underline-offset-4 group-hover:decoration-white">
Upvote &amp; comment <span aria-hidden="true">&rarr;</span>
</span>
</a>
) : null}
<div className="relative z-50 mx-auto w-full max-w-6xl px-4 pt-6 sm:px-6 md:pt-8"> <div className="relative z-50 mx-auto w-full max-w-6xl px-4 pt-6 sm:px-6 md:pt-8">
<div className="relative mx-auto max-w-5xl"> <div className="relative mx-auto max-w-5xl">
<nav className="grid min-h-14 grid-cols-[1fr_auto] items-center gap-3 rounded-full border border-[var(--color-border-subtle)] bg-white/90 px-4 py-2.5 shadow-sm shadow-neutral-900/5 backdrop-blur md:grid-cols-[1fr_auto_1fr] md:px-5"> <nav className="grid min-h-14 grid-cols-[1fr_auto] items-center gap-3 rounded-full border border-[var(--color-border-subtle)] bg-white/90 px-4 py-2.5 shadow-sm shadow-neutral-900/5 backdrop-blur md:grid-cols-[1fr_auto_1fr] md:px-5">