Верхняя навигация и маршрутизация страниц
Верхняя панель навигации — основной путь перемещения пользователя между функциональными разделами. EpoCanvas Docs хранит все навигационные элементы в одном конфигурационном файле: изменение в одном месте действует на весь сайт, при этом точно подсвечивается текущая страница и работает механизм перенаправления старых ссылок.
Центр настройки навигации (src/config/navigation.ts)
Все кнопки верхней навигации поддерживаются в виде декларативного массива в src/config/navigation.ts. Поля каждого элемента определены следующим образом:
// Определение свойств элемента навигацииexport interface NavItem { id: string; // уникальный идентификатор labelKey: string; // имя ключа в многоязычном словаре переводов defaultLabel: string; // текст, отображаемый по умолчанию (например, «Главная», «О продукте») href: string; // ссылка перехода или относительный путь match?: (pathname: string) => boolean; // правило, определяющее, должна ли подсвечиваться эта кнопка на текущей странице badge?: string; // дополнительная маленькая капсульная метка (например, номер версии "v1.2.0") isExternal?: boolean; // является ли переход внешним (если да, открывается в новом окне)}Текущая официальная конфигурация (фрагмент)
export const navigationConfig: NavItem[] = [ { id: 'home', labelKey: 'nav.home', defaultLabel: '首页', href: '/', match: (pathname: string) => pathname === '/' || pathname === '', }, { id: 'docs', labelKey: 'nav.docs', defaultLabel: '产品说明', href: '/canvas/', match: (pathname: string) => pathname === '/canvas' || pathname === '/canvas/' || pathname.includes('about') || pathname.includes('layout') || pathname.includes('search-engine') || pathname.includes('i18n') || pathname.includes('navigation'), }, { id: 'quickstart', labelKey: 'nav.quickstart', defaultLabel: '快速上手', href: '/canvas/deployment/', match: (pathname: string) => pathname.includes('deployment'), }, // Далее следуют guide (правила написания), deploy (развёртывание), faq (частые вопросы) // а также внешний элемент release, ведущий на GitHub Releases];Чтобы добавить или удалить элемент навигации, достаточно добавить или удалить запись в этом массиве; после сохранения локальный сервер разработки автоматически выполнит горячее обновление.
Правила динамической активации и подсветки
Если бы проверка сводилась к простому pathname.startsWith('/canvas'), то при открытии страницы быстрого старта /canvas/deployment/ могли бы подсветиться одновременно обе кнопки — «О продукте» и «Быстрый старт», что вводит в заблуждение.
Поэтому каждый элемент навигации объявляет свою зону подсветки функцией match:
- при открытии главной страницы
/активна только кнопка «Главная»; - при открытии обычных документов вроде
/canvas/layout/,/canvas/about/активируется кнопка «О продукте»; - при переходе на страницы с путём
deploymentисключительно активируется кнопка «Быстрый старт»; - активная кнопка имеет капсульную подложку цвета темы и заметно контрастирует с неактивными.
Добавляя новую страницу документации, не забудьте включить ключевое слово пути в правило match соответствующего элемента навигации, иначе верхняя панель не будет подсвечиваться правильно.
Внешние ссылки и поведение бейджа версии
Если элемент навигации ведёт на внешний сайт (например, на страницу Releases репозитория GitHub):
- задайте
isExternal: true; - система автоматически добавит ссылке защитные атрибуты
target="_blank" rel="noopener noreferrer"и откроет её в новой вкладке; - рядом с текстом появится маленький значок стрелки, направленной наружу (
↗), предупреждающий читателя, что по клику он покинет текущий сайт.
Бейдж версии — капсула внутри кнопки; текст берётся из CURRENT_DOCS_VERSION в src/config/navigation.ts, который читает поле version файла package.json напрямую. При выпуске достаточно поправить только package.json, шапка обновится сама. Клик по бейджу открывает список релизов на GitHub. Полная процедура — в разделе Управление версиями и автоматизация.
Правила перенаправления страниц (astro.config.mjs)
В ходе развития проекта пути документов неизбежно меняются. Чтобы старые ссылки из закладок читателей не превращались в ошибку 404, зарегистрируйте соответствие старых и новых путей в таблице redirects в astro.config.mjs:
export default defineConfig({ redirects: { // После семантического переименования путей разделов сайта все старые ссылки сохраняются и перенаправляются '/canvas/rule-engine': '/canvas/cloudflare/', '/canvas/dns-setup': '/canvas/layout/', },});Astro при сборке генерирует для этих путей страницы автоматического перенаправления: читатель, открывший старый адрес, плавно попадает на новый, а вес в поисковых системах также наследуется.
Почему на боевом сайте отдаётся 301
Страницы перенаправления, которые генерирует Astro, — это документы meta-refresh со статусом 200, и поисковики считают их второй копией цели. Cloudflare Pages читает файл _redirects в корне сайта раньше, чем статические файлы, поэтому cloudflareRedirectsFile() в astro.config.mjs после сборки пишет dist/_redirects из той же таблицы legacyRedirects:
/mail /canvas/ 301/mail/ /canvas/ 301Правила отличаются лишь завершающим слэшем: Cloudflare сопоставляет пути точно, и запрос со слэшем не попадает под правило без него, а значит упал бы на ту страницу 200. Локальный pnpm run preview файл _redirects не читает и по-прежнему использует страницу Astro, так что оба механизма сосуществуют.
Старый путь регистрируйте без завершающего слэша: Astro рендерит его как <старый путь>/index.html, а если добавить и вариант со слэшем в redirects, оба свернутся в один маршрут, о чем сборка сообщит предупреждением route collision (в следующем мажорном Astro это станет ошибкой).