Skip to content

Instantly share code, notes, and snippets.

@shakyShane
Last active June 9, 2026 08:17
Show Gist options
  • Select an option

  • Save shakyShane/b998b1c4722380f4d02281dcafab905f to your computer and use it in GitHub Desktop.

Select an option

Save shakyShane/b998b1c4722380f4d02281dcafab905f to your computer and use it in GitHub Desktop.
Agent prompt: rebrand BTF → turbo-shared via composition/injection (static-pages only)

Agent Prompt: Rebrand BTF → turbo-shared (static-pages only)

Goal

Move (not copy) static-pages rebrand below-the-fold into packages/turbo-shared/src/btf/, then rewire static-pages only (mobile + desktop homepage variants) to consume it. home-mobile is out of scope for this task.

The refactor must surface and remove implicit environment coupling. BTF sections must not depend on static-pages-only contexts, stores, or global hooks. Side effects and consumer-specific behaviour belong at the composition boundary, injected via props, slots, or small effect components — not inside leaf sections.

Success = static-pages mobile + desktop homepages render BTF identically to today, with BTF living in turbo-shared and ready for home-mobile later without further architectural work.

This PR must not leave duplicates. Every file that moves to turbo-shared must be deleted (or reduced to a thin re-export wrapper) from static-pages. The git diff should read as a relocate, not a fork.


Scope

Source (rebrand only — ignore legacy):

  • apps/static-pages/src/components/pages/home-rebrand/in-app-home-below-the-fold.tsx
  • apps/static-pages/src/components/pages/home-rebrand/promotional-home-below-the-fold.tsx
  • apps/static-pages/src/components/pages/home-rebrand/download-options.tsx
  • apps/static-pages/src/components/rebrand/product-showcase.tsx
  • apps/static-pages/src/pages/[locale]/app/index.tsx (component only — strip page exports)
  • Walk import graph from those roots; move all required files + SCSS + assets (PNGs, SVGs) that are BTF-only consumers

Do not use: apps/static-pages/src/components/pages/home/ (legacy)

Consumers to rewire (static-pages only):

  • Mobile: home-rebrand/minimal-homepage.tsxInAppHomeBelowTheFold
  • Desktop promotional: home-rebrand/desktop-homepage.tsxPromotionalHomeBelowTheFold
  • Desktop minimal: same InAppHomeBelowTheFold as mobile

Do not touch: apps/home-mobile, apps/home-desktop, apps/nextssg


Move, don't copy (mandatory)

We have been burned by duplicate trees before. This PR is a single relocation of BTF ownership to turbo-shared.

Do Don't
git mv (or equivalent) files into packages/turbo-shared/src/btf/ Copy files and leave originals in static-pages
Delete moved source files from static-pages Keep parallel implementations
Leave only thin wrappers in static-pages (~15 lines) that import from @staticpages/turbo-shared/btf Leave full component implementations in static-pages
Update all import paths to point at turbo-shared Re-export from old paths without deleting the body

Git diff expectation: For each BTF component/asset, you should see:

  • packages/turbo-shared/src/btf/...added (or renamed from static-pages path)
  • apps/static-pages/src/...deleted or reduced to a thin injection wrapper

If a file under apps/static-pages is still shared by non-BTF code (e.g. a rebrand component used by /app page AND homepage BTF), do not duplicate it — either:

  1. Move it to turbo-shared only if BTF is the sole consumer, or
  2. Leave it in static-pages and import it from there temporarily, with a // TODO: evaluate shared ownership — but prefer moving when BTF is the only consumer.

Assets & icons: If an asset/SVG is only referenced by the BTF subtree, move it into turbo-shared/src/btf/assets/ (or btf/icons/) and delete the static-pages copy. Update imports within btf/ only. Do not leave two copies on disk.

/static-assets/... URL paths (served from turbo-public) stay as-is — those are not repo files to move.


Architecture (mandatory)

Three layers inside turbo-shared/src/btf/:

sections/       — presentational; NO @hooks, NO @stores, NO @contexts
body/           — BtfSharedBody: ProductShowcase + AppEmbed; slot-driven
compositions/   — variant wrappers + side-effect bundles
  mobile-in-app.tsx       → BelowTheFoldInApp
  desktop-promotional.tsx → BelowTheFoldPromotional
shell/          — BtfShell: wrapper styles, id, testId, BtfContext provider

Public exports:

export { BelowTheFoldInApp } from "./compositions/mobile-in-app";
export { BelowTheFoldPromotional } from "./compositions/desktop-promotional";
export { BtfSharedBody } from "./body"; // for Storybook

Add turbo-shared package.json export: "./btf": "./src/btf/index.tsx"


Injection contract (the deliberate refactor)

BtfShell accepts injected dependencies and provides them via a narrow BtfContext (not a recreation of _app):

type BtfInjectedProps = {
  id?: string;
  testId?: string;
  decorateUrl: (url: string) => string;
  firePixel: (id: string, params?: Record<string, unknown>) => void;
  LinkComponent: React.ComponentType<{
    href: string;
    children: React.ReactNode;
    onClick?: () => void;
    className?: string;
  }>;
  device: Device | null; // passed from parent useDevice() — sections do NOT call useDevice from static-pages
};

Rules:

  • Sections call useBtfContext() for decorateUrl, firePixel, Link, device — never @hooks, @stores, @contexts, @utils/pixel directly
  • Every @hooks / @stores / @contexts import found during port → refactor to context injection OR move to compositions/*/effects.tsx
  • If refactor is unclear: leave // TODO: side-effect — needs injection + console.warn — do not silently keep static-pages coupling

Slots on BtfSharedBody:

slots?: {
  prelude?: React.ReactNode;   // in-app: DownloadOptions + heading
  hero?: React.ReactNode;      // in-app: faux browser; promotional: unsupported hero
};
pixels?: { impression?: boolean; scroll?: boolean; bounce?: boolean }; // AppEmbed flags

Compositions pass different slots; shared body stays identical.

Side effects as explicit effect components in compositions only:

// compositions/effects.tsx — hooks live HERE, not in sections
<OriginContentEffect content="details" />
<AtbCampaignEffect page="home" />
<MotionConfig reducedMotion="user" />

static-pages passes real implementations into BtfInjectedProps from its existing runtime (origin-store, Pixel class, Link component, useDevice).


static-pages rewire pattern

Replace moved files with thin wrappers — no BTF logic remains in static-pages:

// home-rebrand/in-app-home-below-the-fold.tsx becomes ~15 lines
import { BelowTheFoldInApp } from "@staticpages/turbo-shared/btf";
import { useDevice } from "@hooks";
import { decorateOriginInUrl } from "@utils/origin";
import { useOriginWithReadyState } from "@hooks/use-origin";
import Link from "@components/link";
import Pixel from "@utils/pixel";

export default function InAppHomeBelowTheFold() {
  const device = useDevice();
  const originState = useOriginWithReadyState();
  if (!device) return null;

  return (
    <BelowTheFoldInApp
      device={device}
      decorateUrl={(url) =>
        originState.isOriginReady
          ? decorateOriginInUrl(url, (o) => o.setIfEmpty("content", "details"))
          : url
      }
      firePixel={(id, params) => new Pixel(id, { params }).fire()}
      LinkComponent={Link}
    />
  );
}

Same pattern for promotional-home-below-the-fold.tsxBelowTheFoldPromotional.

Remove OriginCustomizerProvider from minimal-homepage.tsx / desktop-homepage.tsx if BelowTheFold* compositions own OriginContentEffect.


Verification (static-pages only)

  • /home/mobile BTF matches pre-refactor (visual + data-testid="homepage-btf", download-options, belowTheFold)
  • Desktop promotional homepage BTF works (PromotionalHomeBelowTheFold path)
  • Desktop minimal homepage BTF works (InAppHomeBelowTheFold path)
  • BTF CTA origins still contain __details where expected today
  • No @hooks / @stores / @contexts imports remain inside turbo-shared/src/btf/sections/ or body/
  • No duplicate BTF files — grep static-pages for moved component bodies; only thin wrappers should remain
  • Optional: add Storybook story for BtfSharedBody with mock injection props (no Chromatic ignore needed for isolated story)

Pragmatism

  • Mechanical move first; refactor boundaries as you fix broken imports
  • Ugly internals in btf/ are fine if sections are clean and injections are explicit
  • // TODO + console.warn acceptable for uncertain side effects — document what env assumption was found
  • The point of this task is cleanliness: every removed @hooks import is a discovered coupling; log them in PR description
  • Add turbo-shared deps as needed: @staticpages/design-system, motion, react-intersection-observer, etc.

Done when: static-pages mobile + desktop BTF renders from @staticpages/turbo-shared/btf, moved source files are deleted from static-pages (not duplicated), zero coupling to static-pages internals inside btf/sections or btf/body, and home-mobile could adopt the same exports by passing its own injection props without further structural work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment