{"id":498498,"date":"2026-10-13T17:43:49","date_gmt":"2026-10-13T14:43:49","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=498498"},"modified":"2026-10-13T17:43:49","modified_gmt":"2026-10-13T14:43:49","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=498498","title":{"rendered":"URL \u043d\u0430 \u0434\u0432\u0430 \u0440\u0435\u0436\u0438\u043c\u0430, modal \u043f\u043e\u0432\u0435\u0440\u0445 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 SEO detail page \u0432 Next.js App Router"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 \u043e\u0431\u044b\u0447\u043d\u043e \u0432\u0435\u0434\u0451\u0442 \u043d\u0430 detail page. \u0414\u043b\u044f \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0443\u0436\u0435\u043d \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 URL \u0432\u0440\u043e\u0434\u0435\u00a0<code>\/events\/123<\/code>. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043a\u0430\u0440\u0442\u043e\u0447\u0435\u043a \u043f\u043e\u0434\u0440\u044f\u0434 \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u044c detail \u043f\u043e\u0432\u0435\u0440\u0445 \u043d\u0435\u0433\u043e. \u0415\u0441\u043b\u0438 modal \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u00a0<code>useState<\/code>, \u0430\u0434\u0440\u0435\u0441 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u041f\u0440\u044f\u043c\u0443\u044e \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f. \u041f\u043e\u0441\u043b\u0435 reload \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a, \u0430 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0440\u043e\u0431\u043e\u0442 \u0432\u0438\u0434\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.<br \/>App Router \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0434\u0440\u0443\u0433\u0443\u044e \u0441\u0445\u0435\u043c\u0443. \u041e\u0434\u0438\u043d detail URL \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a modal \u043f\u0440\u0438 client-side \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043f\u0440\u0438 \u043f\u0440\u044f\u043c\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0438\u043b\u0438 reload. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f Parallel Routes \u0438 Intercepting Routes. Next.js \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0434\u043b\u044f modal \u043f\u043e\u0432\u0435\u0440\u0445 gallery \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430. \u0412 \u0443\u0447\u0435\u0431\u043d\u043e\u043c\u00a0<a href=\"https:\/\/eventmap-seo.vercel.app\/en\" rel=\"noopener nofollow\">EventMap<\/a>\u00a0\u044d\u0442\u043e\u0442 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439.<\/p>\n<h3>\u041e\u0434\u0438\u043d URL \u0438 \u0434\u0432\u0430 \u0432\u0445\u043e\u0434\u0430<\/h3>\n<p>\u041f\u0443\u0441\u0442\u044c detail route \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"typescript\">\/en\/events\/london-music-night<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u043d\u0430 \u043d\u0435\u0433\u043e \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438.<br \/>\u0418\u0437 \u0441\u043f\u0438\u0441\u043a\u0430:<\/p>\n<pre><code class=\"typescript\">\/en\/search\/music        \u2193 click\/en\/events\/london-music-night<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u043c\u0435\u043d\u044f\u0435\u0442 URL, \u043d\u043e detail \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0435\u0440\u0445 search page.<br \/>\u041f\u0440\u044f\u043c\u043e\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434:<\/p>\n<pre><code class=\"typescript\">address bar \/ external link \/ reload        \u2193\/en\/events\/london-music-night<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0420\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0430\u044f detail page.<br \/>Intercepting Routes \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442 client-side \u0438 hard navigation. \u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0447\u0435\u0440\u0435\u0437 Next.js router \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c layout. \u041f\u0440\u0438 \u043f\u0440\u044f\u043c\u043e\u043c \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u0438\u043b\u0438 refresh interception \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043f\u043e \u044d\u0442\u043e\u043c\u0443 URL.<br \/>URL \u0432 \u043e\u0431\u043e\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u044e.<\/p>\n<h3>\u041e\u0431\u044b\u0447\u043d\u0430\u044f detail page<\/h3>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0443\u0436\u0435\u043d \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u044b\u0439 route, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u0435\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 modal:<\/p>\n<pre><code class=\"typescript\">app\/  [locale]\/    events\/      [id]\/        page.tsx<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 detail page \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u00a0<code>locale<\/code>\u00a0\u0438\u00a0<code>id<\/code>, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u00a0<code>404<\/code>, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430:<\/p>\n<pre><code class=\"typescript\">export default async function EventDetailPage({  params,}: EventDetailPageProps) {  const locale = await getLocaleFromParams(params);  const { id } = await params;  const event = await fetchEventById({    id,    locale,  });  if (!event) {    notFound();  }  return (    &lt;section className=\"container demo-page\"&gt;      &lt;EventDetails        event={event}        locale={locale}        mode=\"page\"      \/&gt;    &lt;\/section&gt;  );}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e\u0442 route \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u043b \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0435\u0440\u0435\u0434 \u043d\u0438\u043c search page.<br \/>\u0414\u043b\u044f controlled IDs \u043f\u0440\u043e\u0435\u043a\u0442 \u0442\u0430\u043a\u0436\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 static params:<\/p>\n<pre><code class=\"typescript\">export const dynamicParams = true;export function generateStaticParams() {  return getStaticEventParams();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0418\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0435 IDs \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f dynamic routes.<\/p>\n<h3>Metadata detail page<\/h3>\n<p>Detail route \u0432\u043b\u0430\u0434\u0435\u0435\u0442 metadata \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<pre><code class=\"typescript\">export async function generateMetadata({  params,}: EventDetailPageProps): Promise&lt;Metadata&gt; {  const locale = await getLocaleFromParams(params);  const { id } = await params;  const event = await fetchEventById({    id,    locale,  });  const seoPaths =    buildEventSeoPaths({      id,      locale,    });  if (!event) {    return getEventNotFoundMetadata(locale);  }  return toNextMetadata({    title: event.title,    description:      `${event.description} ${event.venue}, ${event.city}.`,    imageUrl: event.imageUrl,    ...seoPaths,  });}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>buildEventSeoPaths<\/code>\u00a0\u0441\u0442\u0440\u043e\u0438\u0442 canonical \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 locale \u0438 ID:<\/p>\n<pre><code class=\"typescript\">export function buildEventSeoPaths({  id,  locale,}: {  id: string;  locale: Locale;}): SeoPaths {  const getPath =    (targetLocale: Locale) =&gt;      routes.eventDetail(        targetLocale,        id,      );  return {    canonicalPath: getPath(locale),    languageAlternates:      buildLocalizedAlternates(getPath),  };}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 canonical \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u00a0<code>\/en\/events\/...<\/code>, \u0434\u043b\u044f \u0440\u0443\u0441\u0441\u043a\u043e\u0439 \u043d\u0430\u00a0<code>\/ru\/events\/...<\/code>. Language alternates \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0442 \u043e\u0431\u0435 \u0432\u0435\u0440\u0441\u0438\u0438.<br \/>Modal \u043d\u0435 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u044d\u0442\u043e\u0442 route. \u041f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0440\u043e\u0431\u043e\u0442 \u0438\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u0443\u044e detail page.<\/p>\n<h3>Parallel Route \u0434\u043b\u044f modal<\/h3>\n<p>Modal \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\u0439. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e App Router \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 named slot \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c\u00a0<code>@<\/code>.<br \/>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code class=\"typescript\">app\/  [locale]\/    layout.tsx    events\/      [id]\/        page.tsx    @modal\/      default.tsx      page.tsx      [...catchAll]\/        page.tsx      (.)events\/        [id]\/          page.tsx<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>@modal<\/code>\u00a0\u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0435\u0433\u043c\u0435\u043d\u0442 \u0432 URL. Named slots \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u043c\u0443 layout \u043a\u0430\u043a props \u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u044f\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441\u00a0<code>children<\/code>.<br \/>Layout \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0432\u0430 React tree:<\/p>\n<pre><code class=\"typescript\">type LocaleLayoutProps = {  children: React.ReactNode;  modal: React.ReactNode;  params: LocaleParams;};export default async function LocaleLayout({  children,  modal,  params,}: LocaleLayoutProps) {  const locale =    await getLocaleFromParams(params);  const messages =    (      await import(        `..\/..\/..\/messages\/${locale}.json`      )    ).default;  return (    &lt;html lang={locale}&gt;      &lt;body&gt;        &lt;NextIntlClientProvider          locale={locale}          messages={messages}        &gt;          &lt;PageShell locale={locale}&gt;            {children}          &lt;\/PageShell&gt;          {modal}        &lt;\/NextIntlClientProvider&gt;      &lt;\/body&gt;    &lt;\/html&gt;  );}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>children<\/code>\u00a0\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 search page \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0443\u044e \u043e\u0431\u044b\u0447\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.\u00a0<code>modal<\/code>\u00a0\u043c\u043e\u0436\u0435\u0442 \u0432\u0435\u0440\u043d\u0443\u0442\u044c overlay \u043b\u0438\u0431\u043e\u00a0<code>null<\/code>.<\/p>\n<h3>Intercepted route<\/h3>\n<p>\u0424\u0430\u0439\u043b modal \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d \u0437\u0434\u0435\u0441\u044c:<\/p>\n<pre><code class=\"typescript\">@modal\/  (.)events\/    [id]\/      page.tsx<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>(.)<\/code>\u00a0\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 interception \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430 \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 route level.<\/p>\n<p><code>@modal<\/code>\u00a0\u043f\u0440\u0438 \u043f\u043e\u0434\u0441\u0447\u0451\u0442\u0435 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f URL segment. \u041f\u043e\u044d\u0442\u043e\u043c\u0443\u00a0<code>(.)events<\/code>\u00a0\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0<code>\/events\/[id]<\/code>, \u0445\u043e\u0442\u044f \u0432 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043f\u0430\u043f\u043a\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0443\u0440\u043e\u0432\u043d\u044f\u0445. \u042d\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0433\u043e\u0432\u043e\u0440\u0435\u043d\u043e \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Next.js.<br \/>Intercepted page \u0441\u043d\u043e\u0432\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0435 route params:<\/p>\n<pre><code class=\"typescript\">type EventPreviewModalPageProps = {  params: Promise&lt;{    id: string;    locale: string;  }&gt;;  searchParams: Promise&lt;    Record&lt;      string,      string | string[] | undefined    &gt;  &gt;;};<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0442\u0435\u043c \u0436\u0435 server function:<\/p>\n<pre><code class=\"typescript\">const locale =  await getLocaleFromParams(params);const { id } = await params;const event =  await fetchEventById({    id,    locale,  });<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Modal route \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e client-side fetch.<\/p>\n<h3>Modal \u043f\u043e\u0432\u0435\u0440\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b<\/h3>\n<p>Intercepted page \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 fixed overlay:<\/p>\n<pre><code class=\"typescript\">return (  &lt;div className=\"modal-backdrop\"&gt;    &lt;aside      className=\"modal-panel event-modal-preview\"      aria-label=\"Event preview\"    &gt;      &lt;EventDetails        event={event}        locale={locale}        mode=\"modal\"      \/&gt;    &lt;\/aside&gt;  &lt;\/div&gt;);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>CSS \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442 backdrop \u043f\u043e\u0432\u0435\u0440\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e content:<\/p>\n<pre><code class=\"typescript\">.modal-backdrop {  position: fixed;  z-index: 40;  inset: 0;  display: grid;  align-items: start;  justify-items: center;  background: rgba(10, 10, 15, 0.74);  padding: 72px 20px 28px;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0432\u00a0<code>children<\/code>, modal \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u0439 slot.<\/p>\n<h3>\u0421\u0441\u044b\u043b\u043a\u0430 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430<\/h3>\n<p>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0435 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 modal URL. \u041e\u043d\u0430 \u0441\u0442\u0440\u043e\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 detail address:<\/p>\n<pre><code class=\"typescript\">const detailHref =  routes.eventDetail(    locale,    event.id,  );<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0<code>Link<\/code>:<\/p>\n<pre><code class=\"typescript\">&lt;Link  className=\"event-card-link\"  href={href}  scroll={false}&gt;  {cardContent}&lt;\/Link&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>Link<\/code>\u00a0\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 client-side navigation. \u041f\u0440\u0438 \u0442\u0430\u043a\u043e\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435\u00a0<code>(.)events\/[id]<\/code>\u00a0\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 route, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 detail \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u00a0<code>@modal<\/code>.<br \/><code>scroll={false}<\/code>\u00a0\u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043f\u043e\u043f\u044b\u0442\u043a\u0443 Next.js \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e page \u043a \u043d\u0430\u0447\u0430\u043b\u0443. \u0421\u0430\u043c\u00a0<code>href<\/code>\u00a0\u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f detail URL.<\/p>\n<h3>\u0424\u0438\u043b\u044c\u0442\u0440\u044b \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u00a0returnTo<\/h3>\n<p>Search page \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043a\u00a0<code>\/search<\/code>.<br \/>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"typescript\">\/en\/search\/music\/en\/search\/music\/london\/en\/search\/music?q=jazz&amp;page=2<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0434 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435\u043c \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 search URL:<\/p>\n<pre><code class=\"typescript\">const returnTo =  buildSearchHref({    filters,    locale,  });<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0418 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0435\u0433\u043e \u0432 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0443:<\/p>\n<pre><code class=\"typescript\">&lt;EventCard  event={event}  key={event.id}  locale={locale}  returnTo={returnTo}\/&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a detail URL:<\/p>\n<pre><code class=\"typescript\">const href = returnTo  ? `${detailHref}?${new URLSearchParams({      returnTo,    }).toString()}`  : detailHref;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0410\u0434\u0440\u0435\u0441 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"typescript\">\/en\/events\/123?returnTo=%2Fen%2Fsearch%2Fmusic%3Fpage%3D2<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>returnTo<\/code>\u00a0\u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430, \u0430 \u043d\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 React-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430.<\/p>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u00a0returnTo<\/h3>\n<p>Query parameter \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f redirect \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438.<br \/>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 modal route \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u00a0<code>searchParams<\/code>\u00a0\u0432 helper:<\/p>\n<pre><code class=\"typescript\">const returnTo =  getSafeReturnTo({    fallback:      routes.search(locale),    locale,    searchParams: query,  });<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Helper \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0439 locale:<\/p>\n<pre><code class=\"typescript\">if (  returnTo !== `\/${locale}` &amp;&amp;  !returnTo.startsWith(`\/${locale}\/`)) {  return fallback;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0442\u043e\u043c URL \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 local origin:<\/p>\n<pre><code class=\"typescript\">const parsed =  new URL(    returnTo,    \"https:\/\/eventmap.local\",  );if (  parsed.origin !==  \"https:\/\/eventmap.local\") {  return fallback;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f pathname, search \u0438 hash:<\/p>\n<pre><code class=\"typescript\">return (  `${parsed.pathname}` +  `${parsed.search}` +  `${parsed.hash}`);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Modal \u0437\u043d\u0430\u0435\u0442 \u0442\u043e\u0447\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441, \u043a\u0443\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044f.<\/p>\n<h3>\u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 modal<\/h3>\n<p>Next.js \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 intercepted modal \u0447\u0435\u0440\u0435\u0437\u00a0<code>router.back()<\/code>\u00a0\u0438\u043b\u0438 \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0<code>Link<\/code>.<\/p>\n<p>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f\u00a0<code>Link<\/code>\u00a0\u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0439\u00a0<code>returnTo<\/code>:<\/p>\n<pre><code class=\"typescript\">&lt;Link  className=\"button button--secondary\"  href={returnTo}  scroll={false}&gt;  Close&lt;\/Link&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0424\u0438\u043b\u044c\u0442\u0440\u044b \u0438 \u043d\u043e\u043c\u0435\u0440 search page \u0443\u0436\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 URL. \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c\u0438 \u0434\u043b\u044f modal \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f.<\/p>\n<h3>default.tsx<\/h3>\n<p>Parallel Route \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u043b\u0443\u0447\u0430\u044f, \u043a\u043e\u0433\u0434\u0430 modal \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u0435\u043d.<\/p>\n<pre><code class=\"typescript\">export default function DefaultModalSlot() {  return null;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041d\u0430 hard navigation Next.js \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c active state unmatched slot. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u00a0<code>default.tsx<\/code>; \u0431\u0435\u0437 \u043d\u0435\u0433\u043e unmatched slot \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a\u00a0<code>404<\/code>. \u0414\u043b\u044f \u043e\u0431\u044b\u0447\u043d\u043e\u0439 detail page\u00a0<code>@modal<\/code>\u00a0\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u00a0<code>null<\/code>.<\/p>\n<h3>page.tsx\u00a0\u0438 catch-all<\/h3>\n<p>\u0423 slot \u0435\u0441\u0442\u044c \u0435\u0449\u0451 \u0434\u0432\u0430 \u043f\u0443\u0441\u0442\u044b\u0445 route:<\/p>\n<pre><code class=\"typescript\">\/\/ @modal\/page.tsxexport default function EmptyModalSlot() {  return null;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0418:<\/p>\n<pre><code class=\"typescript\">\/\/ @modal\/[...catchAll]\/page.tsxexport default function EmptyModalSlot() {  return null;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Parallel Routes \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442 active subpage slot \u043f\u0440\u0438 soft navigation. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 route, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c modal, slot \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441 route, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u043c\u00a0<code>null<\/code>. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f Next.js \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 catch-all \u043f\u043e \u0442\u043e\u0439 \u0436\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u0435.<\/p>\n<h3>Full page \u0438\u0437 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0433\u043e modal<\/h3>\n<p>\u0412 modal \u0435\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435:<\/p>\n<pre><code class=\"typescript\">&lt;a  className=\"button\"  href={    routes.eventDetail(      locale,      event.id,    )  }&gt;  Open full page&lt;\/a&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0<code>&lt;a&gt;<\/code>, \u0430 \u043d\u0435\u00a0<code>next\/link<\/code>. \u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 full-page navigation. Interception \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0438 \u0442\u043e\u0442 \u0436\u0435\u00a0<code>\/events\/[id]<\/code>\u00a0\u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 detail route.<br \/>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u0432\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0430 \u043e\u0434\u0438\u043d pathname:<\/p>\n<pre><code class=\"typescript\">&lt;Link href=\"\/events\/123\"&gt;client navigation\u2192 intercepted modal<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<pre><code class=\"typescript\">&lt;a href=\"\/events\/123\"&gt;hard navigation\u2192 full detail page<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u0440\u044f\u043c\u043e\u0439 \u0432\u0432\u043e\u0434 URL \u0438 reload \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0435\u0442\u043a\u0435.<\/p>\n<h3>\u041e\u0431\u0449\u0438\u0439\u00a0EventDetails<\/h3>\n<p>Modal \u0438 full page \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 \u043e\u0434\u0438\u043d\u00a0<code>event<\/code>, \u043d\u043e \u0432\u044b\u0432\u043e\u0434\u044f\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u043e\u0431\u044a\u0451\u043c\u044b \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438.<br \/>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 mode:<\/p>\n<pre><code class=\"typescript\">type EventDetailsProps = {  actions?: ReactNode;  event: EventCardData;  labels?: EventDetailsLabels;  locale: Locale;  mode: \"modal\" | \"page\";};<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Full page \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442:<\/p>\n<pre><code class=\"typescript\">&lt;EventDetails  event={event}  locale={locale}  mode=\"page\"\/&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Intercepted route \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442:<\/p>\n<pre><code class=\"typescript\">&lt;EventDetails  event={event}  locale={locale}  mode=\"modal\"\/&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0412\u00a0<code>page<\/code>\u00a0mode \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 hero image,\u00a0<code>h1<\/code>, \u043f\u043e\u043b\u043d\u044b\u0439 description, \u0434\u0430\u0442\u0443, venue, category, price \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 actions. \u0412\u00a0<code>modal<\/code>\u00a0mode \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f preview image,\u00a0<code>h2<\/code>, \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0439 \u0438 \u0441\u043e\u043a\u0440\u0430\u0449\u0451\u043d\u043d\u044b\u0439 description.<br \/>Data model \u0443 \u0434\u0432\u0443\u0445 \u0440\u0435\u0436\u0438\u043c\u043e\u0432 \u043e\u0434\u043d\u0430.<\/p>\n<h3>Fetch \u0434\u043b\u044f \u0434\u0432\u0443\u0445 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432<\/h3>\n<p>Full page \u0438 intercepted route \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u043e\u0434\u043d\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e:<\/p>\n<pre><code class=\"typescript\">fetchEventById({  id,  locale,});<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Modal \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0443\u0436\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u0438 \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u043c client state. \u041f\u0440\u0438 \u043f\u0440\u044f\u043c\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 detail page \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0442\u0435\u043c \u0436\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u042d\u0442\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 controlled \u0438 live events \u0432 \u043e\u0431\u043e\u0438\u0445 \u0440\u0435\u0436\u0438\u043c\u0430\u0445.<\/p>\n<h3>URL modal \u0438 canonical<\/h3>\n<p>\u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438\u0437 search URL \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u044b\u0439\u00a0<code>returnTo<\/code>:<\/p>\n<pre><code class=\"typescript\">\/en\/events\/123?returnTo=...<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>SEO helper \u0435\u0433\u043e \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442:<\/p>\n<pre><code class=\"typescript\">const seoPaths =  buildEventSeoPaths({    id,    locale,  });<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Canonical \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 locale \u0438 ID:<\/p>\n<pre><code class=\"typescript\">\/en\/events\/123<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Search filters \u043d\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e canonical detail page.<br \/>Full route \u0442\u0430\u043a\u0436\u0435 \u0441\u0442\u0440\u043e\u0438\u0442 language alternates \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0436\u0435 event ID:<\/p>\n<pre><code class=\"typescript\">\/en\/events\/123\/ru\/events\/123<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Modal navigation \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0442 \u043a \u0441\u043f\u0438\u0441\u043a\u0443 \u043d\u0435 \u043c\u0435\u043d\u044f\u044e\u0442 \u0430\u0434\u0440\u0435\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 detail page \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442 \u043a\u0430\u043a canonical.<\/p>\n<h3>\u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432 modal<\/h3>\n<p>Detail page \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442:<\/p>\n<pre><code class=\"typescript\">notFound();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Modal \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438. \u0415\u0441\u043b\u0438 preview \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b\u0441\u044f, slot \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f overlay \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438. \u041e\u0431\u044b\u0447\u043d\u0430\u044f full page \u043f\u0440\u0438 \u043f\u0440\u044f\u043c\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0443\u00a0<code>404<\/code>.<br \/>\u041c\u0430\u0440\u0448\u0440\u0443\u0442\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043e\u0434\u0438\u043d data source, \u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0440\u0435\u0436\u0438\u043c\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f.<\/p>\n<h3>Search page \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c route<\/h3>\n<p>Modal \u043d\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 search page \u0432 client SPA. Search route \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u043a Server Component:<\/p>\n<pre><code class=\"typescript\">\/[locale]\/search\/[[...segments]]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0424\u0438\u043b\u044c\u0442\u0440\u044b \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0438\u0437\u00a0<code>params<\/code>\u00a0\u0438\u00a0<code>searchParams<\/code>, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 detail URL \u0438\u00a0<code>returnTo<\/code>. Modal \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u0439 Parallel Route slot.<br \/>\u041d\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e client store, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c:<\/p>\n<pre><code class=\"typescript\">selectedEventisModalOpenpreviousSearchFilterspreviousPage<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u042d\u0442\u0438 \u0447\u0430\u0441\u0442\u0438 \u0443\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b route state.<\/p>\n<h3>\u041f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043f\u043e \u0448\u0430\u0433\u0430\u043c<\/h3>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442:<\/p>\n<pre><code class=\"javascript\">\/en\/search\/music?page=2<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Search page \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442:<\/p>\n<pre><code class=\"javascript\">returnTo=\/en\/search\/music?page=2<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0432\u0435\u0434\u0451\u0442 \u043d\u0430:<\/p>\n<pre><code class=\"javascript\">\/en\/events\/123?returnTo=...<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Client-side\u00a0<code>Link<\/code>\u00a0\u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442 intercepted route:<\/p>\n<pre><code class=\"typescript\">@modal\/(.)events\/[id]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>Layout \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 search page \u0438\u00a0<code>@modal<\/code>. Modal \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0447\u0435\u0440\u0435\u0437\u00a0<code>fetchEventById<\/code>. Close \u0432\u0435\u0434\u0451\u0442 \u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0439\u00a0<code>returnTo<\/code>.<br \/>\u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u0442 URL \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 \u043d\u043e\u0432\u043e\u0439 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u0438\u043b\u0438 \u0434\u0435\u043b\u0430\u0435\u0442 reload, Next.js \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 route:<\/p>\n<pre><code class=\"typescript\">events\/[id]\/page.tsx<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 full detail page, metadata, canonical, language alternates \u0438\u00a0<code>404<\/code>\u00a0\u0434\u043b\u044f \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e ID.<\/p>\n<h3>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432<\/h3>\n<p>\u041f\u043e\u043b\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0434\u0435\u0440\u0435\u0432\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"typescript\">app\/\u2514\u2500\u2500 [locale]\/    \u251c\u2500\u2500 layout.tsx    \u2502    \u251c\u2500\u2500 search\/    \u2502   \u2514\u2500\u2500 [[...segments]]\/    \u2502       \u2514\u2500\u2500 page.tsx    \u2502    \u251c\u2500\u2500 events\/    \u2502   \u2514\u2500\u2500 [id]\/    \u2502       \u2514\u2500\u2500 page.tsx    \u2502    \u2514\u2500\u2500 @modal\/        \u251c\u2500\u2500 default.tsx        \u251c\u2500\u2500 page.tsx        \u2502        \u251c\u2500\u2500 [...catchAll]\/        \u2502   \u2514\u2500\u2500 page.tsx        \u2502        \u2514\u2500\u2500 (.)events\/            \u2514\u2500\u2500 [id]\/                \u2514\u2500\u2500 page.tsx<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0<code>events\/[id]<\/code>\u00a0\u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043f\u0440\u044f\u043c\u043e\u0439 detail route \u0438 SEO metadata.\u00a0<code>(.)events\/[id]<\/code>\u00a0\u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 preview \u043f\u0440\u0438 soft navigation.\u00a0<code>@modal<\/code>\u00a0\u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442 preview \u0440\u044f\u0434\u043e\u043c \u0441 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 page.\u00a0<code>default.tsx<\/code>\u00a0\u0438 catch-all \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u043f\u0443\u0441\u0442\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 slot. \u041e\u0431\u0449\u0438\u0439\u00a0<code>EventDetails<\/code>\u00a0\u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0434\u0432\u0443\u0445 \u0440\u0435\u0436\u0438\u043c\u0430\u0445.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1093950\/\">https:\/\/habr.com\/ru\/articles\/1093950\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 \u043e\u0431\u044b\u0447\u043d\u043e \u0432\u0435\u0434\u0451\u0442 \u043d\u0430 detail page. \u0414\u043b\u044f \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0443\u0436\u0435\u043d \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 URL \u0432\u0440\u043e\u0434\u0435\u00a0\/events\/123. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043a\u0430\u0440\u0442\u043e\u0447\u0435\u043a \u043f\u043e\u0434\u0440\u044f\u0434 \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u044c detail \u043f\u043e\u0432\u0435\u0440\u0445 \u043d\u0435\u0433\u043e. \u0415\u0441\u043b\u0438 modal \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u00a0useState, \u0430\u0434\u0440\u0435\u0441 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u041f\u0440\u044f\u043c\u0443\u044e \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f. \u041f\u043e\u0441\u043b\u0435 reload \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a, \u0430 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0440\u043e\u0431\u043e\u0442 \u0432\u0438\u0434\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.App Router \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0434\u0440\u0443\u0433\u0443\u044e \u0441\u0445\u0435\u043c\u0443. \u041e\u0434\u0438\u043d detail URL \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a modal \u043f\u0440\u0438 client-side \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043f\u0440\u0438 \u043f\u0440\u044f\u043c\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0438\u043b\u0438 reload. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f Parallel Routes \u0438 Intercepting Routes. Next.js \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d \u0434\u043b\u044f modal \u043f\u043e\u0432\u0435\u0440\u0445 gallery \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430. \u0412 \u0443\u0447\u0435\u0431\u043d\u043e\u043c\u00a0EventMap\u00a0\u044d\u0442\u043e\u0442 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439.\u041e\u0434\u0438\u043d URL \u0438 \u0434\u0432\u0430 \u0432\u0445\u043e\u0434\u0430\u041f\u0443\u0441\u0442\u044c detail route \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:\/en\/events\/london-music-night\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u043d\u0430 \u043d\u0435\u0433\u043e \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438.\u0418\u0437 \u0441\u043f\u0438\u0441\u043a\u0430:\/en\/search\/music        \u2193 click\/en\/events\/london-music-night\u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u043c\u0435\u043d\u044f\u0435\u0442 URL, \u043d\u043e detail \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0435\u0440\u0445 search page.\u041f\u0440\u044f\u043c\u043e\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434:address bar \/ external link \/ reload        \u2193\/en\/events\/london-music-night\u0420\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0430\u044f detail page.Intercepting Routes \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442 client-side \u0438 hard navigation. \u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0447\u0435\u0440\u0435\u0437 Next.js router \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c layout. \u041f\u0440\u0438 \u043f\u0440\u044f\u043c\u043e\u043c \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u0438\u043b\u0438 refresh interception \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043f\u043e \u044d\u0442\u043e\u043c\u0443 URL.URL \u0432 \u043e\u0431\u043e\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u044e.\u041e\u0431\u044b\u0447\u043d\u0430\u044f detail page\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0443\u0436\u0435\u043d \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u044b\u0439 route, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u0435\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 modal:app\/  [locale]\/    events\/      [id]\/        page.tsx\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 detail page \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u00a0locale\u00a0\u0438\u00a0id, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u00a0404, \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430:export default async function EventDetailPage({  params,}: EventDetailPageProps) {  const locale = await getLocaleFromParams(params);  const { id } = await params;  const event = await fetchEventById({    id,    locale,  });  if (!event) {    notFound();  }  return (    &lt;section className=&#187;container demo-page&#187;&gt;      &lt;EventDetails        event={event}        locale={locale}        mode=&#187;page&#187;      \/&gt;    &lt;\/section&gt;  );}\u042d\u0442\u043e\u0442 route \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u043b \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0435\u0440\u0435\u0434 \u043d\u0438\u043c search page.\u0414\u043b\u044f controlled IDs \u043f\u0440\u043e\u0435\u043a\u0442 \u0442\u0430\u043a\u0436\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 static params:export const dynamicParams = true;export function generateStaticParams() {  return getStaticEventParams();}\u0418\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0435 IDs \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f dynamic routes.Metadata detail pageDetail route \u0432\u043b\u0430\u0434\u0435\u0435\u0442 metadata \u0441\u043e\u0431\u044b\u0442\u0438\u044f.export async function generateMetadata({  params,}: EventDetailPageProps): Promise&lt;Metadata&gt; {  const locale = await getLocaleFromParams(params);  const { id } = await params;  const event = await fetchEventById({    id,    locale,  });  const seoPaths =    buildEventSeoPaths({      id,      locale,    });  if (!event) {    return getEventNotFoundMetadata(locale);  }  return toNextMetadata({    title: event.title,    description:      `${event.description} ${event.venue}, ${event.city}.`,    imageUrl: event.imageUrl,    &#8230;seoPaths,  });}buildEventSeoPaths\u00a0\u0441\u0442\u0440\u043e\u0438\u0442 canonical \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 locale \u0438 ID:export function buildEventSeoPaths({  id,  locale,}: {  id: string;  locale: Locale;}): SeoPaths {  const getPath =    (targetLocale: Locale) =&gt;      routes.eventDetail(        targetLocale,        id,      );  return {    canonicalPath: getPath(locale),    languageAlternates:      buildLocalizedAlternates(getPath),  };}\u0414\u043b\u044f \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 canonical \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u00a0\/en\/events\/&#8230;, \u0434\u043b\u044f \u0440\u0443\u0441\u0441\u043a\u043e\u0439 \u043d\u0430\u00a0\/ru\/events\/&#8230;. Language alternates \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0442 \u043e\u0431\u0435 \u0432\u0435\u0440\u0441\u0438\u0438.Modal \u043d\u0435 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u044d\u0442\u043e\u0442 route. \u041f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0440\u043e\u0431\u043e\u0442 \u0438\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u0443\u044e detail page.Parallel Route \u0434\u043b\u044f modalModal \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\u0439. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e App Router \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 named slot \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c\u00a0@.\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:app\/  [locale]\/    layout.tsx    events\/      [id]\/        page.tsx    @modal\/      default.tsx      page.tsx      [&#8230;catchAll]\/        page.tsx      (.)events\/        [id]\/          page.tsx@modal\u00a0\u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0435\u0433\u043c\u0435\u043d\u0442 \u0432 URL. Named slots \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u043c\u0443 layout \u043a\u0430\u043a props \u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u044f\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441\u00a0children.Layout \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0432\u0430 React tree:type LocaleLayoutProps = {  children: React.ReactNode;  modal: React.ReactNode;  params: LocaleParams;};export default async function LocaleLayout({  children,  modal,  params,}: LocaleLayoutProps) {  const locale =    await getLocaleFromParams(params);  const messages =    (      await import(        `..\/..\/..\/messages\/${locale}.json`      )    ).default;  return (    &lt;html lang={locale}&gt;      &lt;body&gt;        &lt;NextIntlClientProvider          locale={locale}          messages={messages}        &gt;          &lt;PageShell locale={locale}&gt;            {children}          &lt;\/PageShell&gt;          {modal}        &lt;\/NextIntlClientProvider&gt;      &lt;\/body&gt;    &lt;\/html&gt;  );}children\u00a0\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 search page \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0443\u044e \u043e\u0431\u044b\u0447\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.\u00a0modal\u00a0\u043c\u043e\u0436\u0435\u0442 \u0432\u0435\u0440\u043d\u0443\u0442\u044c overlay \u043b\u0438\u0431\u043e\u00a0null.Intercepted route\u0424\u0430\u0439\u043b modal \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d \u0437\u0434\u0435\u0441\u044c:@modal\/  (.)events\/    [id]\/      page.tsx(.)\u00a0\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 interception \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430 \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 route level.@modal\u00a0\u043f\u0440\u0438 \u043f\u043e\u0434\u0441\u0447\u0451\u0442\u0435 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f URL segment. \u041f\u043e\u044d\u0442\u043e\u043c\u0443\u00a0(.)events\u00a0\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0\/events\/[id], \u0445\u043e\u0442\u044f \u0432 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043f\u0430\u043f\u043a\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0443\u0440\u043e\u0432\u043d\u044f\u0445. \u042d\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0433\u043e\u0432\u043e\u0440\u0435\u043d\u043e \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 Next.js.Intercepted page \u0441\u043d\u043e\u0432\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0435 route params:type EventPreviewModalPageProps = {  params: Promise&lt;{    id: string;    locale: string;  }&gt;;  searchParams: Promise&lt;    Record&lt;      string,      string | string[] | undefined    &gt;  &gt;;};\u0414\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f \u0442\u0435\u043c \u0436\u0435 server function:const locale =  await getLocaleFromParams(params);const { id } = await params;const event =  await fetchEventById({    id,    locale,  });Modal route \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e client-side fetch.Modal \u043f\u043e\u0432\u0435\u0440\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044bIntercepted page \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 fixed overlay:return (  &lt;div className=&#187;modal-backdrop&#187;&gt;    &lt;aside      className=&#187;modal-panel event-modal-preview&#187;      aria-label=&#187;Event preview&#187;    &gt;      &lt;EventDetails        event={event}        locale={locale}        mode=&#187;modal&#187;      \/&gt;    &lt;\/aside&gt;  &lt;\/div&gt;);CSS \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442 backdrop \u043f\u043e\u0432\u0435\u0440\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e content:.modal-backdrop {  position: fixed;  z-index: 40;  inset: 0;  display: grid;  align-items: start;  justify-items: center;  background: rgba(10, 10, 15, 0.74);  padding: 72px 20px 28px;}\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0432\u00a0children, modal \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u0439 slot.\u0421\u0441\u044b\u043b\u043a\u0430 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0435 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 modal URL. \u041e\u043d\u0430 \u0441\u0442\u0440\u043e\u0438\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 detail address:const detailHref =  routes.eventDetail(    locale,    event.id,  );\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0Link:&lt;Link  className=&#187;event-card-link&#187;  href={href}  scroll={false}&gt;  {cardContent}&lt;\/Link&gt;Link\u00a0\u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 client-side navigation. \u041f\u0440\u0438 \u0442\u0430\u043a\u043e\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435\u00a0(.)events\/[id]\u00a0\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 route, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 detail \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u00a0@modal.scroll={false}\u00a0\u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043f\u043e\u043f\u044b\u0442\u043a\u0443 Next.js \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e page \u043a \u043d\u0430\u0447\u0430\u043b\u0443. \u0421\u0430\u043c\u00a0href\u00a0\u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f detail URL.\u0424\u0438\u043b\u044c\u0442\u0440\u044b \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u00a0returnToSearch page \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043a\u00a0\/search.\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:\/en\/search\/music\/en\/search\/music\/london\/en\/search\/music?q=jazz&amp;page=2\u041f\u0435\u0440\u0435\u0434 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435\u043c \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 search URL:const returnTo =  buildSearchHref({    filters,    locale,  });\u0418 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0435\u0433\u043e \u0432 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0443:&lt;EventCard  event={event}  key={event.id}  locale={locale}  returnTo={returnTo}\/&gt;\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a detail URL:const href = returnTo  ? `${detailHref}?${new URLSearchParams({      returnTo,    }).toString()}`  : detailHref;\u0410\u0434\u0440\u0435\u0441 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:\/en\/events\/123?returnTo=%2Fen%2Fsearch%2Fmusic%3Fpage%3D2returnTo\u00a0\u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430, \u0430 \u043d\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 React-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430.\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u00a0returnToQuery parameter \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f redirect \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438.\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 modal route \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u00a0searchParams\u00a0\u0432 helper:const returnTo =  getSafeReturnTo({    fallback:      routes.search(locale),    locale,    searchParams: query,  });Helper \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0439 locale:if (  returnTo !== `\/${locale}` &amp;&amp;  !returnTo.startsWith(`\/${locale}\/`)) {  return fallback;}\u041f\u043e\u0442\u043e\u043c URL \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 local origin:const parsed =  new URL(    returnTo,    &#171;https:\/\/eventmap.local&#187;,  );if (  parsed.origin !==  &#171;https:\/\/eventmap.local&#187;) {  return fallback;}\u041d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f pathname, search \u0438 hash:return (  `${parsed.pathname}` +  `${parsed.search}` +  `${parsed.hash}`);Modal \u0437\u043d\u0430\u0435\u0442 \u0442\u043e\u0447\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441, \u043a\u0443\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044f.\u0417\u0430\u043a\u0440\u044b\u0442\u0438\u0435 modalNext.js \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 intercepted modal \u0447\u0435\u0440\u0435\u0437\u00a0router.back()\u00a0\u0438\u043b\u0438 \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0Link.\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f\u00a0Link\u00a0\u043d\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0439\u00a0returnTo:&lt;Link  className=&#187;button button&#8212;secondary&#187;  href={returnTo}  scroll={false}&gt;  Close&lt;\/Link&gt;\u0424\u0438\u043b\u044c\u0442\u0440\u044b \u0438 \u043d\u043e\u043c\u0435\u0440 search page \u0443\u0436\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 URL. \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c\u0438 \u0434\u043b\u044f modal \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f.default.tsxParallel Route \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u043b\u0443\u0447\u0430\u044f, \u043a\u043e\u0433\u0434\u0430 modal \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u0435\u043d.export default function DefaultModalSlot() {  return null;}\u041d\u0430 hard navigation Next.js \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c active state unmatched slot. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u00a0default.tsx; \u0431\u0435\u0437 \u043d\u0435\u0433\u043e unmatched slot \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a\u00a0404. \u0414\u043b\u044f \u043e\u0431\u044b\u0447\u043d\u043e\u0439 detail page\u00a0@modal\u00a0\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u00a0null.page.tsx\u00a0\u0438 catch-all\u0423 slot \u0435\u0441\u0442\u044c \u0435\u0449\u0451 \u0434\u0432\u0430 \u043f\u0443\u0441\u0442\u044b\u0445 route:\/\/ @modal\/page.tsxexport default function EmptyModalSlot() {  return null;}\u0418:\/\/ @modal\/[&#8230;catchAll]\/page.tsxexport default function EmptyModalSlot() {  return null;}Parallel Routes \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442 active subpage slot \u043f\u0440\u0438 soft navigation. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 route, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c modal, slot \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441 route, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u043c\u00a0null. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f Next.js \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 catch-all \u043f\u043e \u0442\u043e\u0439 \u0436\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u0435.Full page \u0438\u0437 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0433\u043e modal\u0412 modal \u0435\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435:&lt;a  className=&#187;button&#187;  href={    routes.eventDetail(      locale,      event.id,    )  }&gt;  Open full page&lt;\/a&gt;\u0417\u0434\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u0439\u00a0&lt;a&gt;, \u0430 \u043d\u0435\u00a0next\/link. \u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 full-page navigation&#8230;.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-498498","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/498498","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=498498"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/498498\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=498498"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=498498"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=498498"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}