All pages

Rebrand the storefront

Files you will touch, in this order:

  1. apps/web/src/config/config.ts, the six identity fields
  2. apps/web/src/routes/index.tsx and the section components it mounts
  3. apps/web/src/routes/about.tsx, privacy-policy.tsx, terms-conditions.tsx and license-agreement.tsx
  4. apps/web/src/components/PostflareMark/PostflareMark.tsx and apps/web/public/
  5. apps/web/src/lib/i18n/locales/*.json, after the English has changed

This is the naming half of making the site yours. Theming is the visual half, and the two do not overlap: nothing below changes a colour.

Set the six identity fields

The whole of src/config/config.ts:

export const appConfig = {
  siteName: 'Postflare',
  wordmark: 'postflare',
  siteUrl: 'https://fast-forward-dev.com',
  contactEmail: 'emillykkeg@gmail.com',
  youtubeUrl: 'https://www.youtube.com/@emilhacking1337',
  description:
    'Upload a video once and publish it to LinkedIn, X, YouTube and more at the same time.',
} as const

What each one drives:

  • siteName is the name in running text: the "Back to" link above every auth form, the header link's accessible name, and the <title> a route inherits when it does not set its own through pageHead().
  • wordmark is how the logo spells the name in the header, the footer and the order summary. Postflare is lowercase in the logo and capitalised in running text.
  • siteUrl is the origin every canonical link, robots.txt and the sitemap are built from.
  • youtubeUrl is the footer's YouTube link. It is one named field rather than a socials map, because a second platform still needs its own markup and icon in Footer.tsx.
  • description is the <meta name="description"> that search results show.

Rewrite the storefront

Everything under src/components/ except src/components/ui/ is yours, in the sense that no upstream will ever merge against it. What follows is the narrower set that sells this product and therefore has to go. The dashboard, admin and checkout components beside it are your product's own interface and stay.

The landing page

routes/index.tsx is a list of sections, and deleting a line deletes a section:

function HomePage() {
  return (
    <NavigationBar>
      <Hero />
      <TechStack />
      <Features />
      <HowItWorks />
      <IconFeatures />
      <AboutShort />
      <Pricing />
      <FAQ />
      <CTA />
    </NavigationBar>
  )
}

Each section owns its own <section> element and its own copy, so a line you delete takes the whole section with it. Motion is kept to what explains something: Hero staggers in on mount, the cards in TechStack arrive once and each plays while it is on screen, the terminal in HowItWorks plays the setup run the first time it is scrolled to, and the four miniatures in Features move only when a reader presses them.

Marketing sections renders each one live with the content it expects. Read it before you decide which to keep, because a section's shape is easier to judge rendered than as a file name.

No section takes its copy as a prop. Each hoists its prose to a const at the top of the file, beside the markup:

// apps/web/src/components/WithOrWithout/WithOrWithout.tsx
const WITHOUT_HEADER = 'Without Fast Forward Dev'
const WITH_HEADER = 'With Fast Forward Dev'

NAV_ITEMS in Header.tsx has the same shape, and it is the one to change rather than delete: its entries hold linkOptions(...), so a nav item pointing at a route you removed is a pnpm typecheck failure and not a dead link.

The pages about Emil

About and AboutShort are one person's biography, and About carries a YouTube embed. They are page content you delete, not components you reuse. AboutShort sits on the landing page, About is the whole of /about, and public/emil.jpg goes with them.

MadeWith.tsx lists projects built on FFD, including this site, with a hard-coded https://fast-forward-dev.com link.

routes/privacy-policy.tsx, routes/terms-conditions.tsx and routes/license-agreement.tsx are FFD's own terms. They name Fast Forward Dev as the licensor, describe a perpetual boilerplate licence, and are governed by the laws of Denmark.

Careful

These pages are not a template for your product. They describe the sale of this repository, and their liability, refund and governing-law clauses are wrong for anything else. Replace them with terms written for what you sell. This page is not legal advice.

Two more route descriptions write the name out: routes/updates.tsx and routes/blog.index.tsx.

The two copy files under src/lib/

lib/catalog/card-copy.ts holds CARD_COPY, one entry per catalog slug, and lib/updates.ts holds AUTHORED, the changelog entries /updates renders.

The mark and the icons

PostflareMark.tsx renders public/postflare-mark.png, the mark Header, Footer, LogoButton and the order summary show, and public/icon.png and public/apple-icon.png are the favicon and the touch icon. All three are exports of the master in docs/brand/, which also records the palette, type and voice.

What stays

src/components/ui/ is the Kit. It names no product and no file in it imports t(). Leave it alone and read Use and extend the Kit when you need a component it does not have.

src/routes/dashboard.tsx, src/routes/admin.tsx, src/routes/checkout.tsx and the auth routes stay, along with the components under src/components/ that they render. So does the rest of src/lib/, apart from the two copy files named above.

Why one surface interpolates the name and another writes it out

AuthShell wraps every sign-in and sign-up form, and you keep it. It reads the name from config:

← {t('Back to {{siteName}}', { siteName: appConfig.siteName })}

WithOrWithout is a landing-page section you rewrite, and it writes the name into the string:

const WITH_HEADER = 'With Fast Forward Dev'

Both shapes are correct, and the test is whether the surface survives your fork. An interpolation in a sentence you keep saves an edit. An interpolation in a sentence you delete saves nothing and costs a reader one more indirection to follow. docs/adr/0035-storefront-copy-is-code-config-holds-identity.md is the decision, including why config stayed this small.

Then run the translation report

pnpm i18n:report

Every English string you rewrote is a new translation key, so the report lists each one. Add the Danish values to src/lib/i18n/locales/da.json, or delete the Danish half of the site. Maintain translations has the mechanics of both.

Note

The report does not list the other half of the change. A Danish entry whose English key no longer exists is not a gap, so the value you orphaned by rewriting a headline stays in da.json until you delete it. Search the file for the old English sentence.

Check it worked

pnpm check && pnpm typecheck

A stray Fast Forward Dev anywhere means one more const to edit:

grep -rn "Fast Forward Dev" apps/web/src --include="*.tsx" --include="*.ts"

The icons under public/ are the one thing left to your own eyes, because grep cannot read a mark drawn inside an image.

Updated