From 60c48e23e5d8ba39c70e58b14ea94355a9bd195e Mon Sep 17 00:00:00 2001 From: Saurabh Date: Sun, 5 Jul 2026 20:17:31 +0530 Subject: [PATCH 1/2] fix: noindex raw registry routes --- app/r/[slug]/raw/route.ts | 1 + app/robots.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/r/[slug]/raw/route.ts b/app/r/[slug]/raw/route.ts index 857c2e8..515d064 100644 --- a/app/r/[slug]/raw/route.ts +++ b/app/r/[slug]/raw/route.ts @@ -24,6 +24,7 @@ export async function GET( "cache-control": "public, max-age=300, s-maxage=3600", "access-control-allow-origin": "*", "access-control-allow-methods": "GET, OPTIONS", + "x-robots-tag": "noindex", "link": `; rel="alternate"; type="application/json"`, }, }); diff --git a/app/robots.ts b/app/robots.ts index 21e04ea..54fa402 100644 --- a/app/robots.ts +++ b/app/robots.ts @@ -10,9 +10,9 @@ export default function robots(): MetadataRoute.Robots { // fetch link-preview images; the more specific allow overrides the // /api/ disallow below. allow: ["/", "/api/og"], - // Machine endpoints: raw source text and the rest of /api/. - // Agents fetch these directly; they are not search content. - disallow: ["/api/", "/r/*/raw"], + // API endpoints do not need crawler traffic. Raw registry source stays + // crawlable so bots can read its X-Robots-Tag: noindex directive. + disallow: ["/api/"], }, ], sitemap: `${SITE}/sitemap.xml`, From ef36659d6b476484a3661a0efeafcf4a558abd0b Mon Sep 17 00:00:00 2001 From: Saurabh Date: Sun, 5 Jul 2026 20:20:58 +0530 Subject: [PATCH 2/2] fix: redirect legacy component URLs --- next.config.mjs | 106 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 8 deletions(-) diff --git a/next.config.mjs b/next.config.mjs index 817858f..09e7e14 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,21 +1,111 @@ -// Components that moved from the motion category to blocks. Old page URLs -// stay alive; install slugs were never category-scoped so /r/* is untouched. -const MOVED_TO_BLOCKS = [ +// Block source files still live under components/motion. Keep inferred and +// historical motion-category URLs pointed at their public block docs pages. +const BLOCK_COMPONENTS = [ "swap", "dynamic-island", "command-palette", "expandable-action-bar", + "overflow-actions", + "expandable-tabs", + "swipeable-list", + "file-upload", + "prediction-market", + "wallet-card", + "otp-input", + "bloom-menu", + "feedback-widget", + "not-found", +]; + +// Old variant and source-file URLs surfaced by crawlers before the catalog was +// consolidated. Send them to the component page that owns the implementation. +const LEGACY_COMPONENT_REDIRECTS = [ + ["/components/motion/base", "/components/motion/button"], + ["/components/motion/button-base", "/components/motion/button"], + ["/components/motion/stateful", "/components/motion/button"], + ["/components/motion/button-stateful", "/components/motion/button"], + ["/components/motion/magnetic", "/components/motion/button"], + ["/components/motion/button-magnetic", "/components/motion/button"], + ["/components/motion/select-morph", "/components/motion/select"], + ["/components/motion/text-reveal", "/components/motion/text-animation"], + ["/components/motion/text-shimmer", "/components/motion/text-animation"], + ["/components/motion/text-cascade", "/components/motion/text-animation"], + ["/components/motion/number-ticker", "/components/motion/number"], + ["/components/motion/animated-number", "/components/motion/number"], + ["/components/motion/action-swap-cascade", "/components/motion/action-swap"], + ["/components/motion/action-swap-blur", "/components/motion/action-swap"], + ["/components/motion/action-swap-roll", "/components/motion/action-swap"], + ["/components/motion/smooth-scroll", "/components/motion/scroll-animation"], + ["/components/motion/scroll-progress", "/components/motion/scroll-animation"], + ["/components/motion/parallax", "/components/motion/scroll-animation"], + ["/components/motion/scroll-to", "/components/motion/scroll-animation"], + ["/components/motion/scroll-reveal", "/components/motion/scroll-animation"], + ["/components/motion/table-editable", "/components/motion/table"], + ["/components/motion/table-async", "/components/motion/table"], + ["/components/motion/editable-cell", "/components/motion/table"], + ["/components/motion/row-handle", "/components/motion/table"], + ["/components/motion/skeleton-rows", "/components/motion/table"], + ["/components/motion/table-header", "/components/motion/table"], + ["/components/motion/table-menu", "/components/motion/table"], + ["/components/motion/use-column-reorder", "/components/motion/table"], + ["/components/motion/use-column-resize", "/components/motion/table"], + ["/components/motion/use-column-sort", "/components/motion/table"], + ["/components/motion/use-row-selection", "/components/motion/table"], + ["/components/motion/create-menu", "/components/blocks/bloom-menu"], + ["/components/blocks/create-menu", "/components/blocks/bloom-menu"], + ["/components/blocks/constants", "/components/blocks/swap"], + ["/components/blocks/controls", "/components/blocks/swap"], + ["/components/blocks/data", "/components/blocks/swap"], + ["/components/blocks/field", "/components/blocks/swap"], + ["/components/blocks/quote-row", "/components/blocks/swap"], + ["/components/blocks/token-badges", "/components/blocks/swap"], + ["/components/blocks/token-picker", "/components/blocks/swap"], + ["/components/blocks/account-avatar", "/components/blocks/wallet-card"], + ["/components/blocks/account-switcher", "/components/blocks/wallet-card"], + ["/components/blocks/actions", "/components/blocks/wallet-card"], + ["/components/blocks/balance-delta", "/components/blocks/wallet-card"], + ["/components/blocks/copy-button", "/components/blocks/wallet-card"], + ["/components/blocks/search-bar", "/components/blocks/wallet-card"], + ["/components/blocks/use-dismiss", "/components/blocks/wallet-card"], + ["/components/blocks/glitch", "/components/blocks/not-found"], + ["/components/blocks/not-found-glitch", "/components/blocks/not-found"], + ["/components/blocks/magnetic", "/components/blocks/not-found"], + ["/components/blocks/not-found-magnetic", "/components/blocks/not-found"], + ["/components/blocks/spotlight", "/components/blocks/not-found"], + ["/components/blocks/not-found-spotlight", "/components/blocks/not-found"], + ["/components/blocks/stacked", "/components/blocks/not-found"], + ["/components/blocks/not-found-stacked", "/components/blocks/not-found"], + ["/components/blocks/terminal", "/components/blocks/not-found"], + ["/components/blocks/not-found-terminal", "/components/blocks/not-found"], + ["/components/blocks/shared", "/components/blocks/not-found"], ]; /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, async redirects() { - return MOVED_TO_BLOCKS.map((slug) => ({ - source: `/components/motion/${slug}`, - destination: `/components/blocks/${slug}`, - permanent: true, - })); + return [ + ...BLOCK_COMPONENTS.map((slug) => ({ + source: `/components/motion/${slug}`, + destination: `/components/blocks/${slug}`, + permanent: true, + })), + ...["swap", "wallet-card", "not-found"].map((slug) => ({ + source: `/components/motion/${slug}/:internal(.+)`, + destination: `/components/blocks/${slug}`, + permanent: true, + })), + ...LEGACY_COMPONENT_REDIRECTS.map(([source, destination]) => ({ + source, + destination, + permanent: true, + })), + { + source: "/components/:category/:slug/:internal(.+)", + destination: "/components/:category/:slug", + permanent: true, + }, + ]; }, outputFileTracingIncludes: { "/components/*": [