Landing Page Configuration
Compose home, features, pricing, FAQ, and legal pages from route files and light config.
Arrange the homepage for your own product: keep the sections you need, replace the copy, and make the navigation lead to useful pages.
Before You Start
Finish Brand Settings. File paths are relative to your selected application's root. Keep dev running to see changes. Public product copy goes in both locales' mvp.json.
A First Edit: Remove the Newsletter Section
Open src/app/(landing-page)/[locale]/(home)/page.tsx. Remove <Newsletter /> and its now-unused import if you do not plan to collect subscriptions yet. Refresh the homepage and confirm the rest of the sections remain in order.
The same approach works for reordering sections: move their JSX. To use a new section, change the import and render that component. Keep the page's existing locale setup and static-rendering configuration. Use the reference below for the other sections and links.
Config Directory Structure
Product config is packages/config/src/index.ts; locale metadata is packages/config/src/i18n.ts. The app config directory only owns pricing display/usage files. Derivative public copy belongs only in packages/i18n/src/translations/{en,zh}/mvp.json; default.json is the template layer.
Home Page
src/app/(landing-page)/[locale]/(home)/page.tsx renders sections sequentially and keeps force-static:
export const dynamic = "force-static";
export default async function Home({ params }) {
const { locale } = await params;
setRequestLocale(locale);
return (
<>
<Hero />
<Features />
<CTASection />
<PricingSection />
<FaqSection />
<Newsletter />
</>
);
}| Section | Component | Notes |
|---|---|---|
| Hero | Hero | Product shot: /images/hero-light.png and /images/hero-dark.png |
| Features | Features | Lucide icons; template copy in default.json; derivative overlays in mvp.json |
| CTA | CTASection | |
| Pricing | PricingSection | Returns null on the homepage when config.payments.enableBilling is false |
| FAQ | FaqSection | Template copy in default.json; derivative overlays in mvp.json |
| Newsletter | Newsletter | Template copy in default.json; derivative overlays in mvp.json |
To hide a section, remove its JSX. To replace a section, change the import. To reorder, move the JSX.
Header and Footer
Edit the link arrays in the components below. Update labels in both locales’ mvp.json so your new links read correctly.
| File | What to change |
|---|---|
src/modules/landing-page/header/SwitchHeader.tsx | Nav links |
src/modules/landing-page/footer/SwitchFooter.tsx | Footer columns, socials, powered-by |
src/modules/landing-page/site-links.ts | GitHub, Discord, X, demo, and powered-by URLs |
packages/i18n/src/translations/{en,zh}/mvp.json | Derivative header/footer labels |
Hide a public page by deleting its link in header/footer. Delete the route file only if the URL should not stay reachable. Pricing links still follow config.payments.enableBilling.
Pricing Page
The pricing page at src/app/(landing-page)/[locale]/pricing/page.tsx is controlled by config.payments.enableBilling. When false, the pricing route redirects to home. Homepage pricing hides itself inside PricingSection instead of using a route-level flag.
Pricing copy and plan display come from src/config/saas/pricing-desc-usage.ts and pricing-desc.ts.
pricing-desc.ts: plan titles, descriptions, and feature listspricing-desc-usage.ts: actual purchasable price items, stable appproductIdvalues, and billing behavior. Provider product IDs are<GATEWAY>_PRODUCT_ID_<PLAN>environment variables.
If you want to show a compare-at/original price such as $249 and charge $199, configure it in pricing-desc-usage.ts:
{
type: "one-time",
productId: billingProductCatalog.lifetime.productId,
originalAmount: 249,
amount: 199,
currency: "USD",
}Field semantics:
amount: the actual checkout amount sent to the billing gatewayoriginalAmount: optional UI-only compare-at price rendered as a strikethrough price in the pricing card
originalAmount is displayed only when it is greater than amount. If omitted, the pricing UI falls back to showing only the current price.
FAQ
FAQ data is defined in src/modules/landing-page/home/components/FaqSection.tsx via two hooks:
useFaqData(): FAQ list (question, answer) — sourced from i18n translationsuseFaqSectionData(): FAQ section title, description — also from i18n
To customize FAQ content in this template, edit default.json in packages/i18n/src/translations/en/ and packages/i18n/src/translations/zh/. Derivative products should put replacement copy in mvp.json instead of overwriting those files.
Changelog
/changelog renders a three-column sticky timeline in src/modules/landing-page/changelog/changelog-page-content.tsx. Entry bodies come from content/changelog/ MDX. UI strings, including the expand-full-notes label, live in default.json; derivative replacements belong in mvp.json.
Legal Pages
Legal pages are independent MDX files. Edit them directly:
| Page | Files |
|---|---|
| Privacy | content/legal/privacy.en.mdx, content/legal/privacy.zh.mdx |
| Terms | content/legal/terms.en.mdx, content/legal/terms.zh.mdx |
| Community | content/legal/behavior.en.mdx, content/legal/behavior.zh.mdx |
Keep frontmatter title. Do not add another # H1 in the body; the route already renders the title. Footer labels live in default.json; derivative replacements belong in mvp.json.
Quick Customization Flow
Edit the JSX list in src/app/(landing-page)/[locale]/(home)/page.tsx to hide, replace, or reorder homepage sections.
Update links in SwitchHeader / SwitchFooter; put derivative navigation copy in both locales’ mvp.json.
Customize derivative FAQ and changelog UI copy via mvp.json, changelog entries via content/changelog/, and legal content via content/legal/.
Related Docs
Basic Configuration
Brand, auth, billing, and contact delivery
Environment Variables
Secrets and payment config
Landing Templates
Drop a Collection issue onto the MuseMVP baseline
Check Your Result
Open both language homepages at desktop and phone widths. Check section order, CTA destinations, header/footer links, FAQ, and pricing visibility. Follow each changed link and check its destination exists. For two-app products, run pnpm apps:parity and synchronize eligible page changes before deploying both.
Common Problems
| Problem | Fix |
|---|---|
| A removed section leaves an import error | Remove its unused import as well as JSX |
| Link labels still use template wording | Overlay the consumed home.* keys in both mvp.json files |
| Hidden page is still reachable | Navigation removal leaves the route available; remove the route only if it must be unavailable |
| Pricing disappears | Check config.payments.enableBilling and your pricing configuration |