Blocks vs Components in the ColoringStore migration
How ColoringStore keeps reusable UI components separate from route-specific product copy during the TanStack migration.
A framework migration gets messy when product copy, route wiring, and reusable UI primitives all live in the same file. ColoringStore keeps the split simple:
A block wires product content into a page. A component renders the props it receives.
Blocks are page wiring
Blocks live in src/blocks/. They read Paraglide messages, choose links, and compose shared components. They are intentionally easy to replace when the product page needs different navigation, a different call to action, or a different information hierarchy.
// src/blocks/header.tsx -- a block: reads i18n and chooses product links
export function Header() {
const navLinks = [
{ href: '/text-to-coloring', label: m['coloring.nav.text_to_coloring']() },
{ href: '/gallery', label: m['coloring.nav.gallery']() },
];
return <SiteHeader navLinks={navLinks} />;
}
Components are durable
Components live in src/components/. SiteHeader, SiteFooter, PricingTable, dialogs, tables, and shadcn/ui primitives should not know the product copy ahead of time. They survive the migration because all labels, links, and content arrive through props.
Why the split matters
ColoringStore can keep upstream SaaS machinery for auth, payments, credits, RBAC, admin, and storage while rewriting the product surface for coloring pages. The migration touches src/routes/, src/blocks/, src/components/coloring/, and messages/ without turning every reusable primitive into one-off project code.